first commit

This commit is contained in:
salam committed 2026-10-19 08:18:39 +02:00
commit 1218dd1517
12716 files changed
+989233

No files matched your search

@@ -0,0 +1,64 @@
<?php
namespace TYPO3\CMS\Extensionmanager\Controller;
/*
* 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!
*/
/**
* Abstract action controller.
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
*/
class AbstractController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController
{
const TRIGGER_RefreshModuleMenu = 'refreshModuleMenu';
const TRIGGER_RefreshTopbar = 'refreshTopbar';
/**
* @var array
*/
protected $triggerArguments = [
self::TRIGGER_RefreshModuleMenu,
self::TRIGGER_RefreshTopbar
];
/**
* Translation shortcut
*
* @param $key
* @param array|null $arguments
* @return string|null
*/
protected function translate($key, $arguments = null)
{
return \TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate($key, 'extensionmanager', $arguments);
}
/**
* Handles trigger arguments, e.g. refreshing the module menu
* widget if an extension with backend modules has been enabled
* or disabled.
*/
protected function handleTriggerArguments()
{
$triggers = [];
foreach ($this->triggerArguments as $triggerArgument) {
if ($this->request->hasArgument($triggerArgument)) {
$triggers[$triggerArgument] = $this->request->getArgument($triggerArgument);
}
}
$this->view->assign('triggers', $triggers);
}
}
@@ -0,0 +1,128 @@
<?php
namespace TYPO3\CMS\Extensionmanager\Controller;
/*
* 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 TYPO3\CMS\Backend\View\BackendTemplateView;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
/**
* Abstract action controller.
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
*/
class AbstractModuleController extends AbstractController
{
/**
* BackendTemplateContainer
*
* @var BackendTemplateView
*/
protected $view;
/**
* Backend Template Container
*
* @var string
*/
protected $defaultViewObjectName = BackendTemplateView::class;
/**
* Resolve view and initialize the general view-variables extensionName,
* controllerName and actionName based on the request object
*
* @return \TYPO3\CMS\Fluid\View\TemplateView
*/
protected function resolveView()
{
$view = parent::resolveView();
$view->assignMultiple([
'extensionName' => $this->request->getControllerExtensionName(),
'controllerName' => $this->request->getControllerName(),
'actionName' => $this->request->getControllerActionName()
]);
return $view;
}
/**
* Generates the action menu
*/
protected function generateMenu()
{
$menuItems = [
'installedExtensions' => [
'controller' => 'List',
'action' => 'index',
'label' => $this->translate('installedExtensions')
]
];
if (!$this->settings['offlineMode'] && !Environment::isComposerMode()) {
$menuItems['getExtensions'] = [
'controller' => 'List',
'action' => 'ter',
'label' => $this->translate('getExtensions')
];
$menuItems['distributions'] = [
'controller' => 'List',
'action' => 'distributions',
'label' => $this->translate('distributions')
];
if ($this->actionMethodName === 'showAllVersionsAction') {
$menuItems['showAllVersions'] = [
'controller' => 'List',
'action' => 'showAllVersions',
'label' => $this->translate('showAllVersions') . ' ' . $this->request->getArgument('extensionKey')
];
}
}
$uriBuilder = $this->objectManager->get(UriBuilder::class);
$uriBuilder->setRequest($this->request);
$menu = $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
$menu->setIdentifier('ExtensionManagerModuleMenu');
foreach ($menuItems as $menuItemConfig) {
if ($this->request->getControllerName() === $menuItemConfig['controller']) {
$isActive = $this->request->getControllerActionName() === $menuItemConfig['action'] ? true : false;
} else {
$isActive = false;
}
$menuItem = $menu->makeMenuItem()
->setTitle($menuItemConfig['label'])
->setHref($this->getHref($menuItemConfig['controller'], $menuItemConfig['action']))
->setActive($isActive);
$menu->addMenuItem($menuItem);
}
$this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
$this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
}
/**
* Creates te URI for a backend action
*
* @param string $controller
* @param string $action
* @param array $parameters
* @return string
*/
protected function getHref($controller, $action, $parameters = [])
{
$uriBuilder = $this->objectManager->get(UriBuilder::class);
$uriBuilder->setRequest($this->request);
return $uriBuilder->reset()->uriFor($action, $parameters, $controller);
}
}
@@ -0,0 +1,185 @@
<?php
namespace TYPO3\CMS\Extensionmanager\Controller;
/*
* 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 TYPO3\CMS\Core\Registry;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Controller for handling extension related actions like
* installing, removing, downloading of data or files
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
*/
class ActionController extends AbstractController
{
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\InstallUtility
*/
protected $installUtility;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
*/
protected $fileHandlingUtility;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\ExtensionModelUtility
*/
protected $extensionModelUtility;
/**
* @var \TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService
*/
protected $managementService;
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\InstallUtility $installUtility
*/
public function injectInstallUtility(\TYPO3\CMS\Extensionmanager\Utility\InstallUtility $installUtility)
{
$this->installUtility = $installUtility;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility
*/
public function injectFileHandlingUtility(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility)
{
$this->fileHandlingUtility = $fileHandlingUtility;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\ExtensionModelUtility $extensionModelUtility
*/
public function injectExtensionModelUtility(\TYPO3\CMS\Extensionmanager\Utility\ExtensionModelUtility $extensionModelUtility)
{
$this->extensionModelUtility = $extensionModelUtility;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService $managementService
*/
public function injectManagementService(\TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService $managementService)
{
$this->managementService = $managementService;
}
/**
* Toggle extension installation state action
*
* @param string $extensionKey
*/
protected function toggleExtensionInstallationStateAction($extensionKey)
{
$installedExtensions = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getLoadedExtensionListArray();
try {
if (in_array($extensionKey, $installedExtensions)) {
// uninstall
$this->installUtility->uninstall($extensionKey);
} else {
// install
$extension = $this->extensionModelUtility->mapExtensionArrayToModel(
$this->installUtility->enrichExtensionWithDetails($extensionKey, false)
);
if ($this->managementService->installExtension($extension) === false) {
$this->redirect('unresolvedDependencies', 'List', null, ['extensionKey' => $extensionKey]);
}
}
} catch (\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException $e) {
$this->addFlashMessage($e->getMessage(), '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
} catch (\TYPO3\CMS\Core\Package\Exception\PackageStatesFileNotWritableException $e) {
$this->addFlashMessage($e->getMessage(), '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
}
$this->redirect('index', 'List', null, [
self::TRIGGER_RefreshModuleMenu => true,
self::TRIGGER_RefreshTopbar => true
]);
}
/**
* Install an extension and omit dependency checking
*
* @param string $extensionKey
*/
public function installExtensionWithoutSystemDependencyCheckAction($extensionKey)
{
$this->managementService->setSkipDependencyCheck(true);
$this->forward('toggleExtensionInstallationState', null, null, ['extensionKey' => $extensionKey]);
}
/**
* Remove an extension (if it is still installed, uninstall it first)
*
* @param string $extension
* @return string
*/
protected function removeExtensionAction($extension)
{
try {
if (\TYPO3\CMS\Core\Core\Environment::isComposerMode()) {
throw new \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException(
'The system is set to composer mode. You are not allowed to remove any extension.',
1590314046
);
}
$this->installUtility->removeExtension($extension);
$this->addFlashMessage(
\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate(
'extensionList.remove.message',
'extensionmanager',
[
'extension' => $extension,
]
)
);
} catch (\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException $e) {
$this->addFlashMessage($e->getMessage(), '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
} catch (\TYPO3\CMS\Core\Package\Exception $e) {
$this->addFlashMessage($e->getMessage(), '', \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR);
}
return '';
}
/**
* Download an extension as a zip file
*
* @param string $extension
*/
protected function downloadExtensionZipAction($extension)
{
$fileName = $this->fileHandlingUtility->createZipFileFromExtension($extension);
$this->fileHandlingUtility->sendZipFileToBrowserAndDelete($fileName);
}
/**
* Reloads the static SQL data of an extension
*
* @param string $extension
*/
protected function reloadExtensionDataAction($extension)
{
$extension = $this->installUtility->enrichExtensionWithDetails($extension, false);
$registryKey = $extension['siteRelPath'] . 'ext_tables_static+adt.sql';
$registry = GeneralUtility::makeInstance(Registry::class);
$registry->remove('extensionDataImport', $registryKey);
$this->installUtility->processExtensionSetup($extension['key']);
$this->redirect('index', 'List');
}
}
@@ -0,0 +1,91 @@
<?php
namespace TYPO3\CMS\Extensionmanager\Controller;
/*
* 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 TYPO3\CMS\Backend\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\View\BackendTemplateView;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
/**
* Controller for distribution related actions
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
*/
class DistributionController extends AbstractModuleController
{
/**
* @var \TYPO3\CMS\Core\Package\PackageManager
*/
protected $packageManager;
/**
* @param \TYPO3\CMS\Core\Package\PackageManager $packageManager
*/
public function injectPackageManager(\TYPO3\CMS\Core\Package\PackageManager $packageManager)
{
$this->packageManager = $packageManager;
}
/**
* Set up the doc header properly here
*
* @param ViewInterface $view
*/
protected function initializeView(ViewInterface $view)
{
if ($view instanceof BackendTemplateView) {
/** @var BackendTemplateView $view */
parent::initializeView($view);
$this->generateMenu();
$this->registerDocheaderButtons();
}
}
/**
* Shows information about the distribution
*
* @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
*/
public function showAction(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension)
{
$extensionKey = $extension->getExtensionKey();
// Check if extension/package is installed
$active = $this->packageManager->isPackageActive($extensionKey);
$this->view->assign('distributionActive', $active);
$this->view->assign('extension', $extension);
}
/**
* Registers the Icons into the docheader
*
* @throws \InvalidArgumentException
*/
protected function registerDocheaderButtons()
{
/** @var ButtonBar $buttonBar */
$buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
$uriBuilder = $this->controllerContext->getUriBuilder();
$uri = $uriBuilder->reset()->uriFor('distributions', [], 'List');
$title = $this->translate('extConfTemplate.backToList');
$icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL);
$button = $buttonBar->makeLinkButton()
->setHref($uri)
->setTitle($title)
->setIcon($icon);
$buttonBar->addButton($button, ButtonBar::BUTTON_POSITION_LEFT);
}
}
@@ -0,0 +1,377 @@
<?php
namespace TYPO3\CMS\Extensionmanager\Controller;
/*
* 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 TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\View\JsonView;
use TYPO3\CMS\Extensionmanager\Domain\Model\Extension;
/**
* Controller for actions related to the TER download of an extension
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
*/
class DownloadController extends AbstractController
{
/**
* @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
*/
protected $extensionRepository;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
*/
protected $fileHandlingUtility;
/**
* @var \TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService
*/
protected $managementService;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\InstallUtility
*/
protected $installUtility;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\DownloadUtility
*/
protected $downloadUtility;
/**
* @var JsonView
*/
protected $defaultViewObjectName = JsonView::class;
/**
* @var JsonView
*/
protected $view;
/**
* @param \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository
*/
public function injectExtensionRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository)
{
$this->extensionRepository = $extensionRepository;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility
*/
public function injectFileHandlingUtility(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility)
{
$this->fileHandlingUtility = $fileHandlingUtility;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService $managementService
*/
public function injectManagementService(\TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService $managementService)
{
$this->managementService = $managementService;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\InstallUtility $installUtility
*/
public function injectInstallUtility(\TYPO3\CMS\Extensionmanager\Utility\InstallUtility $installUtility)
{
$this->installUtility = $installUtility;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\DownloadUtility $downloadUtility
*/
public function injectDownloadUtility(\TYPO3\CMS\Extensionmanager\Utility\DownloadUtility $downloadUtility)
{
$this->downloadUtility = $downloadUtility;
}
/**
* Defines which view object should be used for the installFromTer action
*/
protected function initializeInstallFromTerAction()
{
$this->defaultViewObjectName = \TYPO3\CMS\Fluid\View\TemplateView::class;
}
/**
* Check extension dependencies
*
* @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
* @throws \Exception
*/
public function checkDependenciesAction(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension)
{
$message = '';
$title = '';
$hasDependencies = false;
$hasErrors = false;
$dependencyTypes = null;
$configuration = [
'value' => [
'dependencies' => [],
],
];
$isAutomaticInstallationEnabled = (bool)GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('extensionmanager', 'automaticInstallation');
if (!$isAutomaticInstallationEnabled) {
// if automatic installation is deactivated, no dependency check is needed (download only)
$action = 'installExtensionWithoutSystemDependencyCheck';
} else {
$action = 'installFromTer';
try {
$dependencyTypes = $this->managementService->getAndResolveDependencies($extension);
if (!empty($dependencyTypes)) {
$hasDependencies = true;
$message = '<p>' . $this->translate('downloadExtension.dependencies.headline') . '</p>';
foreach ($dependencyTypes as $dependencyType => $dependencies) {
$extensions = '';
foreach ($dependencies as $extensionKey => $dependency) {
if (!isset($configuration['value']['dependencies'][$dependencyType])) {
$configuration['value']['dependencies'][$dependencyType] = [];
}
$configuration['value']['dependencies'][$dependencyType][$extensionKey] = [
'_exclude' => [
'categoryIndexFromStringOrNumber',
],
];
$extensions .= $this->translate(
'downloadExtension.dependencies.extensionWithVersion',
[
$extensionKey, $dependency->getVersion()
]
) . '<br />';
}
$message .= $this->translate(
'downloadExtension.dependencies.typeHeadline',
[
$this->translate('downloadExtension.dependencyType.' . $dependencyType),
$extensions
]
);
}
$title = $this->translate('downloadExtension.dependencies.resolveAutomatically');
}
} catch (\Exception $e) {
$hasErrors = true;
$title = $this->translate('downloadExtension.dependencies.errorTitle');
$message = $e->getMessage();
}
}
$url = $this->uriBuilder->uriFor(
$action,
['extension' => $extension->getUid(), 'format' => 'json'],
'Download'
);
$this->view->setConfiguration($configuration);
$this->view->assign('value', [
'dependencies' => $dependencyTypes,
'url' => $url,
'message' => $message,
'hasErrors' => $hasErrors,
'hasDependencies' => $hasDependencies,
'title' => $title
]);
}
/**
* Install an extension from TER action
*
* @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
* @param string $downloadPath
*/
public function installFromTerAction(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension, $downloadPath = 'Local')
{
list($result, $errorMessages) = $this->installFromTer($extension, $downloadPath);
$isAutomaticInstallationEnabled = (bool)GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('extensionmanager', 'automaticInstallation');
$this->view
->assign('result', $result)
->assign('extension', $extension)
->assign('installationTypeLanguageKey', $isAutomaticInstallationEnabled ? '' : '.downloadOnly')
->assign('unresolvedDependencies', $errorMessages);
}
/**
* Check extension dependencies with special dependencies
*
* @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
* @throws \Exception
*/
public function installExtensionWithoutSystemDependencyCheckAction(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension)
{
$this->managementService->setSkipDependencyCheck(true);
$this->forward('installFromTer', null, null, ['extension' => $extension, 'downloadPath' => 'Local']);
}
/**
* Action for installing a distribution -
* redirects directly to configuration after installing
*
* @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
*/
public function installDistributionAction(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension)
{
if (!\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('impexp')) {
$this->forward('distributions', 'List');
}
list($result, $errorMessages) = $this->installFromTer($extension);
if ($errorMessages) {
foreach ($errorMessages as $extensionKey => $messages) {
foreach ($messages as $message) {
$this->addFlashMessage(
$message['message'],
\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate(
'distribution.error.headline',
'extensionmanager',
[$extensionKey]
),
\TYPO3\CMS\Core\Messaging\AbstractMessage::ERROR
);
}
}
// Redirect back to distributions list action
$this->redirect(
'distributions',
'List'
);
} else {
// FlashMessage that extension is installed
$this->addFlashMessage(
\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate(
'distribution.welcome.message',
'extensionmanager',
[$extension->getExtensionKey()]
),
\TYPO3\CMS\Extbase\Utility\LocalizationUtility::translate('distribution.welcome.headline', 'extensionmanager')
);
// Redirect to show action
$this->redirect(
'show',
'Distribution',
null,
['extension' => $extension]
);
}
}
/**
* Update an extension. Makes no sanity check but directly searches highest
* available version from TER and updates. Update check is done by the list
* already. This method should only be called if we are sure that there is
* an update.
*
* @return string
*/
protected function updateExtensionAction()
{
$extensionKey = $this->request->getArgument('extension');
$version = $this->request->getArgument('version');
$extension = $this->extensionRepository->findOneByExtensionKeyAndVersion($extensionKey, $version);
if (!$extension instanceof Extension) {
$extension = $this->extensionRepository->findHighestAvailableVersion($extensionKey);
}
$installedExtensions = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getLoadedExtensionListArray();
try {
if (in_array($extensionKey, $installedExtensions, true)) {
// To resolve new dependencies the extension is installed again
$this->managementService->installExtension($extension);
} else {
$this->managementService->downloadMainExtension($extension);
}
$this->addFlashMessage(
$this->translate('extensionList.updateFlashMessage.body', [$extensionKey]),
$this->translate('extensionList.updateFlashMessage.title')
);
} catch (\Exception $e) {
$this->addFlashMessage($e->getMessage(), '', FlashMessage::ERROR);
}
return '';
}
/**
* Show update comments for extensions that can be updated.
* Fetches update comments for all versions between the current
* installed and the highest version.
*/
protected function updateCommentForUpdatableVersionsAction()
{
$extensionKey = $this->request->getArgument('extension');
$versionStart = $this->request->getArgument('integerVersionStart');
$versionStop = $this->request->getArgument('integerVersionStop');
$updateComments = [];
/** @var Extension[] $updatableVersions */
$updatableVersions = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion(
$extensionKey,
$versionStart,
$versionStop,
false
);
$highestPossibleVersion = false;
foreach ($updatableVersions as $updatableVersion) {
if ($highestPossibleVersion === false) {
$highestPossibleVersion = $updatableVersion->getVersion();
}
$updateComments[$updatableVersion->getVersion()] = $updatableVersion->getUpdateComment();
}
$this->view->assign('value', [
'updateComments' => $updateComments,
'url' => $this->uriBuilder->uriFor(
'updateExtension',
['extension' => $extensionKey, 'version' => $highestPossibleVersion]
)
]);
}
/**
* Install an extension from TER
* Downloads the extension, resolves dependencies and installs it
*
* @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension
* @param string $downloadPath
* @return array
*/
protected function installFromTer(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extension, $downloadPath = 'Local')
{
$result = false;
$errorMessages = [];
try {
$this->downloadUtility->setDownloadPath($downloadPath);
$isAutomaticInstallationEnabled = (bool)GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('extensionmanager', 'automaticInstallation');
$this->managementService->setAutomaticInstallationEnabled($isAutomaticInstallationEnabled);
if (($result = $this->managementService->installExtension($extension)) === false) {
$errorMessages = $this->managementService->getDependencyErrors();
}
} catch (\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException $e) {
$errorMessages = [
$extension->getExtensionKey() => [
[
'code' => $e->getCode(),
'message' => $e->getMessage(),
]
],
];
}
return [$result, $errorMessages];
}
}
@@ -0,0 +1,292 @@
<?php
namespace TYPO3\CMS\Extensionmanager\Controller;
/*
* 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 TYPO3\CMS\Backend\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\View\BackendTemplateView;
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
use TYPO3\CMS\Extensionmanager\Utility\ExtensionModelUtility;
use TYPO3\CMS\Extensionmanager\Utility\Repository\Helper;
/**
* Controller for extension listings (TER or local extensions)
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
*/
class ListController extends AbstractModuleController
{
/**
* @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
*/
protected $extensionRepository;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\ListUtility
*/
protected $listUtility;
/**
* @var \TYPO3\CMS\Core\Page\PageRenderer
*/
protected $pageRenderer;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility
*/
protected $dependencyUtility;
/**
* @param \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository
*/
public function injectExtensionRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository)
{
$this->extensionRepository = $extensionRepository;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility
*/
public function injectListUtility(\TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility)
{
$this->listUtility = $listUtility;
}
/**
* @param \TYPO3\CMS\Core\Page\PageRenderer $pageRenderer
*/
public function injectPageRenderer(\TYPO3\CMS\Core\Page\PageRenderer $pageRenderer)
{
$this->pageRenderer = $pageRenderer;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility
*/
public function injectDependencyUtility(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility)
{
$this->dependencyUtility = $dependencyUtility;
}
/**
* Add the needed JavaScript files for all actions
*/
public function initializeAction()
{
$this->pageRenderer->addInlineLanguageLabelFile('EXT:extensionmanager/Resources/Private/Language/locallang.xlf');
$isAutomaticInstallationEnabled = (bool)GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('extensionmanager', 'offlineMode');
if ($isAutomaticInstallationEnabled) {
$this->settings['offlineMode'] = true;
}
}
/**
* Set up the doc header properly here
*
* @param ViewInterface $view
*/
protected function initializeView(ViewInterface $view)
{
if ($view instanceof BackendTemplateView) {
/** @var BackendTemplateView $view */
parent::initializeView($view);
$this->generateMenu();
$this->registerDocheaderButtons();
}
}
/**
* Adds an information about composer mode
*/
protected function addComposerModeNotification()
{
if (Environment::isComposerMode()) {
$this->addFlashMessage(
LocalizationUtility::translate(
'composerMode.message',
'extensionmanager'
),
LocalizationUtility::translate(
'composerMode.title',
'extensionmanager'
),
FlashMessage::INFO
);
}
}
/**
* Shows list of extensions present in the system
*/
public function indexAction()
{
$this->addComposerModeNotification();
$availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensionsWithAdditionalInformation();
ksort($availableAndInstalledExtensions);
$this->view->assignMultiple(
[
'extensions' => $availableAndInstalledExtensions,
'isComposerMode' => Environment::isComposerMode(),
]
);
$this->handleTriggerArguments();
}
/**
* Shows a list of unresolved dependency errors with the possibility to bypass the dependency check
*
* @param string $extensionKey
* @throws ExtensionManagerException
*/
public function unresolvedDependenciesAction($extensionKey)
{
$availableExtensions = $this->listUtility->getAvailableExtensions();
if (isset($availableExtensions[$extensionKey])) {
$extensionArray = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation(
[
$extensionKey => $availableExtensions[$extensionKey]
]
);
/** @var ExtensionModelUtility $extensionModelUtility */
$extensionModelUtility = $this->objectManager->get(ExtensionModelUtility::class);
$extension = $extensionModelUtility->mapExtensionArrayToModel($extensionArray[$extensionKey]);
} else {
throw new ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1402421007);
}
$this->dependencyUtility->checkDependencies($extension);
$this->view->assign('extension', $extension);
$this->view->assign('unresolvedDependencies', $this->dependencyUtility->getDependencyErrors());
}
/**
* Shows extensions from TER
* Either all extensions or depending on a search param
*
* @param string $search
*/
public function terAction($search = '')
{
$this->addComposerModeNotification();
$search = trim($search);
if (!empty($search)) {
$extensions = $this->extensionRepository->findByTitleOrAuthorNameOrExtensionKey($search);
} else {
$extensions = $this->extensionRepository->findAll();
}
$availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensions($this->listUtility->getAvailableExtensions());
$this->view->assign('extensions', $extensions)
->assign('search', $search)
->assign('availableAndInstalled', $availableAndInstalledExtensions);
}
/**
* Action for listing all possible distributions
*
* @param bool $showUnsuitableDistributions
*/
public function distributionsAction($showUnsuitableDistributions = false)
{
$this->addComposerModeNotification();
$importExportInstalled = ExtensionManagementUtility::isLoaded('impexp');
if ($importExportInstalled) {
try {
/** @var Helper $repositoryHelper */
$repositoryHelper = $this->objectManager->get(Helper::class);
// Check if a TER update has been done at all, if not, fetch it directly
// Repository needs an update, but not because of the extension hash has changed
$isExtListUpdateNecessary = $repositoryHelper->isExtListUpdateNecessary();
if ($isExtListUpdateNecessary > 0 && ($isExtListUpdateNecessary & $repositoryHelper::PROBLEM_EXTENSION_HASH_CHANGED) === 0) {
$repositoryHelper->updateExtList();
}
} catch (ExtensionManagerException $e) {
$this->addFlashMessage($e->getMessage(), $e->getCode(), FlashMessage::ERROR);
}
$officialDistributions = $this->extensionRepository->findAllOfficialDistributions();
$communityDistributions = $this->extensionRepository->findAllCommunityDistributions();
$officialDistributions = $this->dependencyUtility->filterYoungestVersionOfExtensionList($officialDistributions->toArray(), $showUnsuitableDistributions);
$communityDistributions = $this->dependencyUtility->filterYoungestVersionOfExtensionList($communityDistributions->toArray(), $showUnsuitableDistributions);
$this->view->assign('officialDistributions', $officialDistributions);
$this->view->assign('communityDistributions', $communityDistributions);
}
$this->view->assign('enableDistributionsView', $importExportInstalled);
$this->view->assign('showUnsuitableDistributions', $showUnsuitableDistributions);
}
/**
* Shows all versions of a specific extension
*
* @param string $extensionKey
*/
public function showAllVersionsAction($extensionKey)
{
$currentVersion = $this->extensionRepository->findOneByCurrentVersionByExtensionKey($extensionKey);
$extensions = $this->extensionRepository->findByExtensionKeyOrderedByVersion($extensionKey);
$this->view->assignMultiple(
[
'extensionKey' => $extensionKey,
'currentVersion' => $currentVersion,
'extensions' => $extensions
]
);
}
/**
* Registers the Icons into the docheader
*
* @throws \InvalidArgumentException
*/
protected function registerDocheaderButtons()
{
if (Environment::isComposerMode()) {
return;
}
if (!in_array($this->actionMethodName, ['indexAction', 'terAction', 'showAllVersionsAction'], true)) {
return;
}
/** @var ButtonBar $buttonBar */
$buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
$uriBuilder = $this->controllerContext->getUriBuilder();
if ($this->actionMethodName === 'showAllVersionsAction') {
$uri = $uriBuilder->reset()->uriFor('ter', [], 'List');
$title = $this->translate('extConfTemplate.backToList');
$icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL);
$classes = '';
} else {
$uri = $uriBuilder->reset()->uriFor('form', [], 'UploadExtensionFile');
$title = $this->translate('extensionList.uploadExtension');
$icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-edit-upload', Icon::SIZE_SMALL);
$classes = 't3js-upload';
}
$button = $buttonBar->makeLinkButton()
->setHref($uri)
->setTitle($title)
->setClasses($classes)
->setIcon($icon);
$buttonBar->addButton($button, ButtonBar::BUTTON_POSITION_LEFT);
}
}
@@ -0,0 +1,129 @@
<?php
namespace TYPO3\CMS\Extensionmanager\Controller;
/*
* 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 TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Extbase\Mvc\View\JsonView;
/**
* Controller for actions relating to update of full extension list from TER
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
*/
class UpdateFromTerController extends AbstractController
{
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\Repository\Helper
*/
protected $repositoryHelper;
/**
* @var \TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository
*/
protected $repositoryRepository;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\ListUtility
*/
protected $listUtility;
/**
* @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
*/
protected $extensionRepository;
/**
* @var JsonView
*/
protected $defaultViewObjectName = JsonView::class;
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\Repository\Helper $repositoryHelper
*/
public function injectRepositoryHelper(\TYPO3\CMS\Extensionmanager\Utility\Repository\Helper $repositoryHelper)
{
$this->repositoryHelper = $repositoryHelper;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository $repositoryRepository
*/
public function injectRepositoryRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\RepositoryRepository $repositoryRepository)
{
$this->repositoryRepository = $repositoryRepository;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility
*/
public function injectListUtility(\TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility)
{
$this->listUtility = $listUtility;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository
*/
public function injectExtensionRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository)
{
$this->extensionRepository = $extensionRepository;
}
/**
* Update extension list from TER
*
* @param bool $forceUpdateCheck
*/
public function updateExtensionListFromTerAction($forceUpdateCheck = false)
{
$updated = false;
$errorMessage = '';
if ($this->extensionRepository->countAll() === 0 || $forceUpdateCheck) {
try {
$updated = $this->repositoryHelper->updateExtList();
} catch (\TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException $e) {
$errorMessage = $e->getMessage();
}
}
/** @var \TYPO3\CMS\Extensionmanager\Domain\Model\Repository $repository */
$repository = $this->repositoryRepository->findOneTypo3OrgRepository();
$timeFormat = $this->getLanguageService()->sL('LLL:EXT:extensionmanager/Resources/Private/Language/locallang.xlf:extensionList.updateFromTer.lastUpdate.fullTimeFormat');
$lastUpdateTime = $repository ? $repository->getLastUpdate() : null;
if (null === $lastUpdateTime) {
$lastUpdatedSince = $this->getLanguageService()->sL('LLL:EXT:extensionmanager/Resources/Private/Language/locallang.xlf:extensionList.updateFromTer.never');
$lastUpdateTime = date($timeFormat);
} else {
$lastUpdatedSince = \TYPO3\CMS\Backend\Utility\BackendUtility::calcAge(
time() - $lastUpdateTime->format('U'),
$this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.minutesHoursDaysYears')
);
$lastUpdateTime = $lastUpdateTime->format($timeFormat);
}
$this->view->assign('value', [
'updated' => $updated,
'lastUpdateTime' => $lastUpdateTime,
'timeSinceLastUpdate' => $lastUpdatedSince,
'errorMessage' => $errorMessage
]);
}
/**
* @return LanguageService
*/
protected function getLanguageService()
{
return $GLOBALS['LANG'];
}
}
@@ -0,0 +1,79 @@
<?php
namespace TYPO3\CMS\Extensionmanager\Controller;
/*
* 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 TYPO3\CMS\Backend\Template\Components\ButtonBar;
use TYPO3\CMS\Backend\View\BackendTemplateView;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
/**
* Controller for configuration related actions.
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
*/
class UpdateScriptController extends AbstractModuleController
{
/**
* Set up the doc header properly here
*
* @param ViewInterface $view
*/
protected function initializeView(ViewInterface $view)
{
if ($view instanceof BackendTemplateView) {
/** @var BackendTemplateView $view */
parent::initializeView($view);
$this->generateMenu();
$this->registerDocheaderButtons();
}
}
/**
* Show the content of the update script (if any).
*
* @param string $extensionKey Extension key
* @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
*/
public function showAction($extensionKey)
{
/** @var \TYPO3\CMS\Extensionmanager\Utility\UpdateScriptUtility $updateScriptUtility */
$updateScriptUtility = $this->objectManager->get(\TYPO3\CMS\Extensionmanager\Utility\UpdateScriptUtility::class);
$updateScriptResult = $updateScriptUtility->executeUpdateIfNeeded($extensionKey);
$this->view
->assign('updateScriptResult', $updateScriptResult)
->assign('extensionKey', $extensionKey);
}
/**
* Registers the Icons into the docheader
*
* @throws \InvalidArgumentException
*/
protected function registerDocheaderButtons()
{
/** @var ButtonBar $buttonBar */
$buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
$uriBuilder = $this->controllerContext->getUriBuilder();
$uri = $uriBuilder->reset()->uriFor('index', [], 'List');
$title = $this->translate('extConfTemplate.backToList');
$icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL);
$button = $buttonBar->makeLinkButton()
->setHref($uri)
->setTitle($title)
->setIcon($icon);
$buttonBar->addButton($button, ButtonBar::BUTTON_POSITION_LEFT);
}
}
@@ -0,0 +1,352 @@
<?php
namespace TYPO3\CMS\Extensionmanager\Controller;
/*
* 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 TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Security\BlockSerializationTrait;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extensionmanager\Exception\DependencyConfigurationNotFoundException;
use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
/**
* Controller for handling upload of a local extension file
* Handles .t3x or .zip files
* @internal This class is a specific controller implementation and is not considered part of the Public TYPO3 API.
*/
class UploadExtensionFileController extends AbstractController
{
use BlockSerializationTrait;
/**
* @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
*/
protected $extensionRepository;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility
*/
protected $fileHandlingUtility;
/**
* @var \TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility
*/
protected $terUtility;
/**
* @var \TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService
*/
protected $managementService;
/**
* @var string
*/
protected $extensionBackupPath = '';
/**
* @var bool
*/
protected $removeFromOriginalPath = false;
/**
* @param \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository
*/
public function injectExtensionRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository)
{
$this->extensionRepository = $extensionRepository;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility
*/
public function injectFileHandlingUtility(\TYPO3\CMS\Extensionmanager\Utility\FileHandlingUtility $fileHandlingUtility)
{
$this->fileHandlingUtility = $fileHandlingUtility;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility $terUtility
*/
public function injectTerUtility(\TYPO3\CMS\Extensionmanager\Utility\Connection\TerUtility $terUtility)
{
$this->terUtility = $terUtility;
}
/**
* @param \TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService $managementService
*/
public function injectManagementService(\TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService $managementService)
{
$this->managementService = $managementService;
}
/**
* Remove backup folder before destruction
*/
public function __destruct()
{
$this->removeBackupFolder();
}
/**
* Render upload extension form
*/
public function formAction()
{
if (Environment::isComposerMode()) {
throw new ExtensionManagerException(
'Composer mode is active. You are not allowed to upload any extension file.',
1444725828
);
}
}
/**
* Extract an uploaded file and install the matching extension
*
* @param bool $overwrite Overwrite existing extension if TRUE
* @throws \TYPO3\CMS\Extbase\Mvc\Exception\StopActionException
*/
public function extractAction($overwrite = false)
{
if (Environment::isComposerMode()) {
throw new ExtensionManagerException(
'Composer mode is active. You are not allowed to upload any extension file.',
1444725853
);
}
$file = $_FILES['tx_extensionmanager_tools_extensionmanagerextensionmanager'];
$fileName = pathinfo($file['name']['extensionFile'], PATHINFO_BASENAME);
try {
// If the file name isn't valid an error will be thrown
$this->checkFileName($fileName);
if (!empty($file['tmp_name']['extensionFile'])) {
$tempFile = GeneralUtility::upload_to_tempfile($file['tmp_name']['extensionFile']);
} else {
throw new ExtensionManagerException(
'Creating temporary file failed. Check your upload_max_filesize and post_max_size limits.',
1342864339
);
}
$extensionData = $this->extractExtensionFromFile($tempFile, $fileName, $overwrite);
$isAutomaticInstallationEnabled = (bool)GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('extensionmanager', 'automaticInstallation');
if (!$isAutomaticInstallationEnabled) {
$this->addFlashMessage(
$this->translate('extensionList.uploadFlashMessage.message', [$extensionData['extKey']]),
$this->translate('extensionList.uploadFlashMessage.title'),
FlashMessage::OK
);
} else {
if ($this->activateExtension($extensionData['extKey'])) {
$this->addFlashMessage(
$this->translate('extensionList.installedFlashMessage.message', [$extensionData['extKey']]),
'',
FlashMessage::OK
);
} else {
$this->redirect('unresolvedDependencies', 'List', null, ['extensionKey' => $extensionData['extKey']]);
}
}
} catch (\TYPO3\CMS\Extbase\Mvc\Exception\StopActionException $exception) {
throw $exception;
} catch (DependencyConfigurationNotFoundException $exception) {
$this->addFlashMessage($exception->getMessage(), '', FlashMessage::ERROR);
} catch (\Exception $exception) {
$this->removeExtensionAndRestoreFromBackup($fileName);
$this->addFlashMessage($exception->getMessage(), '', FlashMessage::ERROR);
}
$this->redirect('index', 'List', null, [
self::TRIGGER_RefreshModuleMenu => true,
self::TRIGGER_RefreshTopbar => true
]);
}
/**
* Validate the filename of an uploaded file
*
* @param string $fileName
* @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
*/
public function checkFileName($fileName)
{
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
if (empty($fileName)) {
throw new ExtensionManagerException('No file given.', 1342858852);
}
if ($extension !== 't3x' && $extension !== 'zip') {
throw new ExtensionManagerException('Wrong file format "' . $extension . '" given. Allowed formats are t3x and zip.', 1342858853);
}
}
/**
* Extract a given t3x or zip file
*
* @param string $uploadPath Path to existing extension file
* @param string $fileName Filename of the uploaded file
* @param bool $overwrite If true, extension will be replaced
* @return array Extension data
* @throws ExtensionManagerException
* @throws DependencyConfigurationNotFoundException
*/
public function extractExtensionFromFile($uploadPath, $fileName, $overwrite)
{
$fileExtension = pathinfo($fileName, PATHINFO_EXTENSION);
if ($fileExtension === 't3x') {
$extensionData = $this->getExtensionFromT3xFile($uploadPath, $overwrite);
} else {
$extensionData = $this->getExtensionFromZipFile($uploadPath, $fileName, $overwrite);
}
return $extensionData;
}
/**
* @param string $extensionKey
* @return bool
*/
public function activateExtension($extensionKey)
{
$this->managementService->reloadPackageInformation($extensionKey);
$extension = $this->managementService->getExtension($extensionKey);
return is_array($this->managementService->installExtension($extension));
}
/**
* Extracts a given t3x file and installs the extension
*
* @param string $file Path to uploaded file
* @param bool $overwrite Overwrite existing extension if TRUE
* @throws ExtensionManagerException
* @throws DependencyConfigurationNotFoundException
* @return array
*/
protected function getExtensionFromT3xFile($file, $overwrite = false)
{
$fileContent = file_get_contents($file);
if (!$fileContent) {
throw new ExtensionManagerException('File had no or wrong content.', 1342859339);
}
$extensionData = $this->terUtility->decodeExchangeData($fileContent);
if (empty($extensionData['extKey'])) {
throw new ExtensionManagerException('Decoding the file went wrong. No extension key found', 1342864309);
}
$isExtensionAvailable = $this->managementService->isAvailable($extensionData['extKey']);
if (!$overwrite && $isExtensionAvailable) {
throw new ExtensionManagerException($this->translate('extensionList.overwritingDisabled'), 1342864310);
}
if ($isExtensionAvailable) {
$this->copyExtensionFolderToTempFolder($extensionData['extKey']);
}
$this->removeFromOriginalPath = true;
$extension = $this->extensionRepository->findOneByExtensionKeyAndVersion($extensionData['extKey'], $extensionData['EM_CONF']['version']);
$this->fileHandlingUtility->unpackExtensionFromExtensionDataArray($extensionData, $extension);
if (empty($extension)
&& empty($extensionData['EM_CONF']['constraints'])
&& !isset($extensionData['FILES']['ext_emconf.php'])
&& !isset($extensionData['FILES']['/ext_emconf.php'])
) {
throw new DependencyConfigurationNotFoundException('Extension cannot be installed automatically because no dependencies could be found! Please check dependencies manually (on typo3.org) before installing the extension.', 1439587168);
}
return $extensionData;
}
/**
* Extracts a given zip file and installs the extension
* As there is no information about the extension key in the zip
* we have to use the file name to get that information
* filename format is expected to be extensionkey_version.zip
*
* @param string $file Path to uploaded file
* @param string $fileName Filename (basename) of uploaded file
* @param bool $overwrite Overwrite existing extension if TRUE
* @return array
* @throws ExtensionManagerException
*/
protected function getExtensionFromZipFile($file, $fileName, $overwrite = false)
{
// Remove version and extension from filename to determine the extension key
$extensionKey = $this->getExtensionKeyFromFileName($fileName);
$isExtensionAvailable = $this->managementService->isAvailable($extensionKey);
if (!$overwrite && $isExtensionAvailable) {
throw new ExtensionManagerException('Extension is already available and overwriting is disabled.', 1342864311);
}
if ($isExtensionAvailable) {
$this->copyExtensionFolderToTempFolder($extensionKey);
}
$this->removeFromOriginalPath = true;
$this->fileHandlingUtility->unzipExtensionFromFile($file, $extensionKey);
return ['extKey' => $extensionKey];
}
/**
* Removes version and file extension from filename to determine extension key
*
* @param string $fileName
* @return string
*/
protected function getExtensionKeyFromFileName($fileName)
{
return preg_replace('/_(\\d+)(\\.|\\-)(\\d+)(\\.|\\-)(\\d+).*/i', '', strtolower(substr($fileName, 0, -4)));
}
/**
* Copies current extension folder to typo3temp directory as backup
*
* @param string $extensionKey
* @throws \TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
*/
protected function copyExtensionFolderToTempFolder($extensionKey)
{
$this->extensionBackupPath = Environment::getVarPath() . '/transient/' . $extensionKey . substr(sha1($extensionKey . microtime()), 0, 7) . '/';
GeneralUtility::mkdir($this->extensionBackupPath);
GeneralUtility::copyDirectory(
$this->fileHandlingUtility->getExtensionDir($extensionKey),
$this->extensionBackupPath
);
}
/**
* Removes the extension directory and restores the extension from the backup directory
*
* @param string $fileName
* @see UploadExtensionFileController::extractAction
*/
protected function removeExtensionAndRestoreFromBackup($fileName)
{
$extDirPath = $this->fileHandlingUtility->getExtensionDir($this->getExtensionKeyFromFileName($fileName));
if ($this->removeFromOriginalPath && is_dir($extDirPath)) {
GeneralUtility::rmdir($extDirPath, true);
}
if (!empty($this->extensionBackupPath)) {
GeneralUtility::mkdir($extDirPath);
GeneralUtility::copyDirectory($this->extensionBackupPath, $extDirPath);
}
}
/**
* Removes the backup folder in typo3temp
*/
protected function removeBackupFolder()
{
if (!empty($this->extensionBackupPath)) {
GeneralUtility::rmdir($this->extensionBackupPath, true);
$this->extensionBackupPath = '';
}
}
}