/** * Save configuration and redirects back to form * or to the welcome page of a distribution * * @param array $config The new extension configuration * @param string $extensionKey The extension key * @return void */ public function saveAction(array $config, $extensionKey) { $this->saveConfiguration($config, $extensionKey); /** @var Extension $extension */ $extension = $this->extensionRepository->findOneByCurrentVersionByExtensionKey($extensionKey); // Different handling for distribution installation if ($extension instanceof Extension && $extension->getCategory() === Extension::DISTRIBUTION_CATEGORY) { $this->redirect('welcome', 'Distribution', NULL, array('extension' => $extension->getUid())); } else { $this->redirect('showConfigurationForm', NULL, NULL, array('extension' => array('key' => $extensionKey))); } }
/** * Update extension list from TER * * @param boolean $forceUpdateCheck * @return void */ 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 $repository \TYPO3\CMS\Extensionmanager\Domain\Model\Repository */ $repository = $this->repositoryRepository->findByUid((int) $this->settings['repositoryUid']); $this->view->assign('updated', $updated)->assign('repository', $repository)->assign('errorMessage', $errorMessage); }
/** * 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; }
/** * Save configuration to file * Merges existing with new configuration. * * @param array $config The new extension configuration * @param string $extensionKey The extension key * @return void */ public function saveAction(array $config, $extensionKey) { /** @var $configurationUtility \TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility */ $configurationUtility = $this->objectManager->get('TYPO3\\CMS\\Extensionmanager\\Utility\\ConfigurationUtility'); $newConfiguration = $configurationUtility->getCurrentConfiguration($extensionKey); \TYPO3\CMS\Core\Utility\ArrayUtility::mergeRecursiveWithOverrule($newConfiguration, $config); $configurationUtility->writeConfiguration($configurationUtility->convertValuedToNestedConfiguration($newConfiguration), $extensionKey); $this->emitAfterExtensionConfigurationWriteSignal($newConfiguration); /** @var Extension $extension */ $extension = $this->extensionRepository->findOneByCurrentVersionByExtensionKey($extensionKey); // Different handling for distribution installation if ($extension instanceof Extension && $extension->getCategory() === Extension::DISTRIBUTION_CATEGORY) { $this->redirect('welcome', 'Distribution', NULL, array('extension' => $extension->getUid())); } else { $this->redirect('showConfigurationForm', NULL, NULL, array('extension' => array('key' => $extensionKey))); } }
/** * Show update comments for extensions that can be updated. * Fetches update comments for all versions between the current * installed and the highest version. * * @return void */ protected function updateCommentForUpdatableVersionsAction() { $extensionKey = $this->request->getArgument('extension'); $version = $this->request->getArgument('integerVersion'); $updateComments = array(); /** @var Extension[] $updatableVersions */ $updatableVersions = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion($extensionKey, $version); foreach ($updatableVersions as $updatableVersion) { $updateComments[$updatableVersion->getVersion()] = $updatableVersion->getUpdateComment(); } $this->view->assign('updateComments', $updateComments)->assign('extensionKey', $extensionKey); }
/** * Shows all versions of a specific extension * * @return void */ public function showAllVersionsAction() { $this->pageRenderer->addJsFile($this->backPath . '../t3lib/js/extjs/notifications.js'); $extensions = array(); $extensionKey = ''; if ($this->request->hasArgument('allVersions') && $this->request->getArgument('allVersions') == 1 && $this->request->hasArgument('extensionKey') && is_string($this->request->getArgument('extensionKey'))) { $extensionKey = $this->request->getArgument('extensionKey'); $extensions = $this->extensionRepository->findByExtensionKeyOrderedByVersion($extensionKey); } else { $this->redirect('ter'); } $this->view->assign('extensions', $extensions)->assign('extensionKey', $extensionKey); }
/** * Checks if an update for an extension is available * * @internal * @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extensionData * @return boolean */ public function isUpdateAvailable(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extensionData) { // Only check for update for TER extensions $version = $extensionData->getIntegerVersion(); /** @var $highestTerVersionExtension \TYPO3\CMS\Extensionmanager\Domain\Model\Extension */ $highestTerVersionExtension = $this->extensionRepository->findHighestAvailableVersion($extensionData->getExtensionKey()); if ($highestTerVersionExtension instanceof \TYPO3\CMS\Extensionmanager\Domain\Model\Extension) { $highestVersion = $highestTerVersionExtension->getIntegerVersion(); if ($highestVersion > $version) { return TRUE; } } return FALSE; }
/** * Fetch an extension from TER. * * @param string $extensionKey The extension key * @param string $location Where to import the extension. System = typo3/sysext, Global = typo3/ext, Local = typo3conf/ext * @param bool $overwrite Overwrite the extension if it already exists * @param int $mirror The mirror to fetch the extension from * * @throws \RuntimeException * @throws \InvalidArgumentException * @return array */ public function fetchExtension($extensionKey, $version = '', $location = 'Local', $overwrite = FALSE, $mirror = -1) { if (!is_numeric($mirror)) { throw new InvalidArgumentException('Option --mirror must be a number. Run the command extensionapi:listmirrors to get the list of all available repositories'); } if ($version === '') { $extension = $this->extensionRepository->findHighestAvailableVersion($extensionKey); if ($extension === NULL) { throw new InvalidArgumentException(sprintf('Extension "%s" was not found on TER', $extensionKey)); } } else { $extension = $this->extensionRepository->findOneByExtensionKeyAndVersion($extensionKey, $version); if ($extension === NULL) { throw new InvalidArgumentException(sprintf('Version %s of extension "%s" does not exist', $version, $extensionKey)); } } if (!$overwrite) { $comingExtPath = $this->fileHandlingUtility->getExtensionDir($extensionKey, $location); if (@is_dir($comingExtPath)) { throw new InvalidArgumentException(sprintf('Extension "%s" already exists at "%s"!', $extensionKey, $comingExtPath)); } } $mirrors = $this->repositoryHelper->getMirrors(); if ($mirrors === NULL) { throw new RuntimeException('No mirrors found!'); } if ($mirror === -1) { $mirrors->setSelect(); } elseif ($mirror > 0 && $mirror <= count($mirrors->getMirrors())) { $mirrors->setSelect($mirror); } else { throw new InvalidArgumentException(sprintf('Mirror "%s" does not exist', $mirror)); } /** * @var \TYPO3\CMS\Extensionmanager\Utility\DownloadUtility $downloadUtility */ $downloadUtility = $this->objectManager->get('TYPO3\\CMS\\Extensionmanager\\Utility\\DownloadUtility'); $downloadUtility->setDownloadPath($location); $this->extensionManagementService->downloadMainExtension($extension); $return = array(); $extensionDir = $this->fileHandlingUtility->getExtensionDir($extensionKey, $location); if (is_dir($extensionDir)) { $return['main']['extKey'] = $extension->getExtensionKey(); $return['main']['version'] = $extension->getVersion(); } else { throw new RuntimeException(sprintf('Extension "%s" version %s could not installed!', $extensionKey, $extension->getVersion())); } return $return; }
/** * Update extension list from TER * * @param bool $forceUpdateCheck * @return void */ 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 $repository \TYPO3\CMS\Extensionmanager\Domain\Model\Repository */ $repository = $this->repositoryRepository->findByUid((int) $this->settings['repositoryUid']); $timeFormat = $this->getLanguageService()->sL('LLL:EXT:extensionmanager/Resources/Private/Language/locallang.xlf:extensionList.updateFromTer.lastUpdate.fullTimeFormat'); $lastUpdateTime = $repository->getLastUpdate(); 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:lang/Resources/Private/Language/locallang_core.xlf:labels.minutesHoursDaysYears')); $lastUpdateTime = $lastUpdateTime->format($timeFormat); } $this->view->assign('value', ['updated' => $updated, 'lastUpdateTime' => $lastUpdateTime, 'timeSinceLastUpdate' => $lastUpdatedSince, 'errorMessage' => $errorMessage]); }
/** * Method initializes parsing of extension.xml.gz file. * * @param string $localExtensionListFile absolute path to extension list xml.gz * @param int $repositoryUid UID of repository when inserting records into DB * @return int total number of imported extension versions */ public function import($localExtensionListFile, $repositoryUid = NULL) { if (!is_null($repositoryUid) && is_int($repositoryUid)) { $this->repositoryUid = $repositoryUid; } $zlibStream = 'compress.zlib://'; $this->sumRecords = 0; $this->parser->parseXML($zlibStream . $localExtensionListFile); // flush last rows to database if existing if (!empty($this->arrRows)) { $GLOBALS['TYPO3_DB']->exec_INSERTmultipleRows('tx_extensionmanager_domain_model_extension', self::$fieldNames, $this->arrRows, self::$fieldIndicesNoQuote); } $extensions = $this->extensionRepository->insertLastVersion($this->repositoryUid); $this->repositoryRepository->updateRepositoryCount($extensions, $this->repositoryUid); return $this->sumRecords; }
/** * Returns the updateable version for an extension which also resolves dependencies. * * @internal * @param Extension $extensionData * @return bool|Extension FALSE if no update available otherwise latest possible update */ public function getUpdateableVersion(Extension $extensionData) { // Only check for update for TER extensions $version = $extensionData->getIntegerVersion(); /** @var $extensionUpdates[] \TYPO3\CMS\Extensionmanager\Domain\Model\Extension */ $extensionUpdates = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion($extensionData->getExtensionKey(), $version + 1); if ($extensionUpdates->count() > 0) { foreach ($extensionUpdates as $extensionUpdate) { $this->dependencyUtility->checkDependencies($extensionUpdate); if (!$this->dependencyUtility->hasDependencyErrors()) { return $extensionUpdate; } } } return FALSE; }
/** * Method initializes parsing of extension.xml.gz file. * * @param string $localExtensionListFile absolute path to extension list xml.gz * @param int $repositoryUid UID of repository when inserting records into DB * @return int total number of imported extension versions */ public function import($localExtensionListFile, $repositoryUid = null) { if (!is_null($repositoryUid) && is_int($repositoryUid)) { $this->repositoryUid = $repositoryUid; } $zlibStream = 'compress.zlib://'; $this->sumRecords = 0; $this->parser->parseXml($zlibStream . $localExtensionListFile); // flush last rows to database if existing if (!empty($this->arrRows)) { GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable('tx_extensionmanager_domain_model_extension')->bulkInsert('tx_extensionmanager_domain_model_extension', $this->arrRows, self::$fieldNames); } $extensions = $this->extensionRepository->insertLastVersion($this->repositoryUid); $this->repositoryRepository->updateRepositoryCount($extensions, $this->repositoryUid); return $this->sumRecords; }
/** * @test * @return void */ public function updateExtensionListFromTerCallsUpdateExtListIfForceUpdateCheckIsSet() { $controllerMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Controller\UpdateFromTerController::class, array('dummy')); $repositoryModelMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Repository::class, array('getLastUpdate')); $viewMock = $this->getAccessibleMock(\TYPO3\CMS\Fluid\View\TemplateView::class, array('assign'), array(), '', FALSE); $requestMock = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Mvc\Request::class, array('hasArgument', 'getArgument')); $viewMock->expects($this->any())->method('assign')->will($this->returnValue($viewMock)); $this->repositoryRepositoryMock->expects($this->once())->method('findByUid')->with(1)->will($this->returnValue($repositoryModelMock)); $this->repositoryHelperMock->expects($this->once())->method('updateExtList'); $this->extensionRepositoryMock->expects($this->once())->method('countAll')->will($this->returnValue(100)); $controllerMock->_set('extensionRepository', $this->extensionRepositoryMock); $controllerMock->_set('repositoryRepository', $this->repositoryRepositoryMock); $controllerMock->_set('repositoryHelper', $this->repositoryHelperMock); $controllerMock->_set('settings', array('repositoryUid' => 1)); $controllerMock->_set('view', $viewMock); $controllerMock->_set('request', $requestMock); $controllerMock->updateExtensionListFromTerAction(TRUE); }
/** * Show update comments for extensions that can be updated. * Fetches update comments for all versions between the current * installed and the highest version. * * @return void */ 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])]); }
/** * Adds the information from the emconf array to the extension information * * @param array $extensions * @return array */ public function enrichExtensionsWithEmConfAndTerInformation(array $extensions) { foreach ($extensions as $extensionKey => $properties) { $emconf = $this->emConfUtility->includeEmConf($properties); if ($emconf) { $extensions[$extensionKey] = array_merge($emconf, $properties); $terObject = $this->extensionRepository->findOneByExtensionKeyAndVersion($extensionKey, $extensions[$extensionKey]['version']); if ($terObject instanceof \TYPO3\CMS\Extensionmanager\Domain\Model\Extension) { $extensions[$extensionKey]['terObject'] = $terObject; $extensions[$extensionKey]['updateAvailable'] = $this->installUtility->isUpdateAvailable($terObject); } } else { unset($extensions[$extensionKey]); } } return $extensions; }
/** * Tries to find given extension with given version in TER data. * If extension is found but not the given version, we return TER data from highest version with version data set to * given one. * * @param string $extensionKey Key of the extension * @param string $version String representation of version number * @return Extension|NULL Extension TER object or NULL if nothing found */ protected function getExtensionTerData($extensionKey, $version) { $terObject = $this->extensionRepository->findOneByExtensionKeyAndVersion($extensionKey, $version); if (!$terObject instanceof Extension) { // Version unknown in TER data, try to find extension $terObject = $this->extensionRepository->findHighestAvailableVersion($extensionKey); if ($terObject instanceof Extension) { // Found in TER now, set version information to the known ones, so we can look if there is a newer one // Use a cloned object, otherwise wrong information is stored in persistenceManager $terObject = clone $terObject; $terObject->setVersion($version); $terObject->setIntegerVersion(VersionNumberUtility::convertVersionNumberToInteger($terObject->getVersion())); } else { $terObject = NULL; } } return $terObject; }
/** * Checks if an update for an extension is available * * @internal * @param \TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extensionData * @return boolean */ public function isUpdateAvailable(\TYPO3\CMS\Extensionmanager\Domain\Model\Extension $extensionData) { $isUpdateAvailable = FALSE; // Only check for update for TER extensions $version = $extensionData->getIntegerVersion(); /** @var $highestTerVersionExtension \TYPO3\CMS\Extensionmanager\Domain\Model\Extension */ $highestTerVersionExtension = $this->extensionRepository->findHighestAvailableVersion($extensionData->getExtensionKey()); if ($highestTerVersionExtension instanceof \TYPO3\CMS\Extensionmanager\Domain\Model\Extension) { $highestVersion = $highestTerVersionExtension->getIntegerVersion(); if ($highestVersion > $version) { $this->dependencyUtility->checkDependencies($highestTerVersionExtension); if (!$this->dependencyUtility->hasDependencyErrors()) { $isUpdateAvailable = TRUE; } } } return $isUpdateAvailable; }
/** * @test * @return void */ public function updateExtensionListFromTerCallsUpdateExtListIfForceUpdateCheckIsSet() { /** @var \PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface|UpdateFromTerController $controllerMock */ $controllerMock = $this->getAccessibleMock(UpdateFromTerController::class, array('getLanguageService')); $controllerMock->expects($this->any())->method('getLanguageService')->will($this->returnValue($this->languageServiceMock)); $repositoryModelMock = $this->getAccessibleMock(\TYPO3\CMS\Extensionmanager\Domain\Model\Repository::class, array('getLastUpdate')); $viewMock = $this->getAccessibleMock(\TYPO3\CMS\Fluid\View\TemplateView::class, array('assign'), array(), '', false); $requestMock = $this->getAccessibleMock(\TYPO3\CMS\Extbase\Mvc\Request::class, array('hasArgument', 'getArgument')); $viewMock->expects($this->any())->method('assign')->will($this->returnValue($viewMock)); $this->repositoryRepositoryMock->expects($this->once())->method('findByUid')->with(1)->will($this->returnValue($repositoryModelMock)); $this->repositoryHelperMock->expects($this->once())->method('updateExtList'); $this->extensionRepositoryMock->expects($this->once())->method('countAll')->will($this->returnValue(100)); $controllerMock->_set('extensionRepository', $this->extensionRepositoryMock); $controllerMock->_set('repositoryRepository', $this->repositoryRepositoryMock); $controllerMock->_set('repositoryHelper', $this->repositoryHelperMock); $controllerMock->_set('settings', array('repositoryUid' => 1)); $controllerMock->_set('view', $viewMock); $controllerMock->_set('request', $requestMock); $controllerMock->updateExtensionListFromTerAction(true); }
/** * Method returns information if currently available * extension list might be outdated. * * @access public * @see Tx_Extensionmanager_Utility_Repository_Helper::PROBLEM_NO_VERSIONS_IN_DATABASE, * @throws ExtensionManagerException * @return int "0" if everything is perfect, otherwise bitmask with problems */ public function isExtListUpdateNecessary() { $updateNecessity = 0; if ($this->extensionRepository->countByRepository($this->repository->getUid()) <= 0) { $updateNecessity |= self::PROBLEM_NO_VERSIONS_IN_DATABASE; } if (!is_file($this->getLocalExtListFile())) { $updateNecessity |= self::PROBLEM_EXTENSION_FILE_NOT_EXISTING; } else { $remotemd5 = \TYPO3\CMS\Core\Utility\GeneralUtility::getUrl($this->getRemoteExtHashFile(), 0, array(TYPO3_user_agent)); if ($remotemd5 !== FALSE) { $localmd5 = md5_file($this->getLocalExtListFile()); if ($remotemd5 !== $localmd5) { $updateNecessity |= self::PROBLEM_EXTENSION_HASH_CHANGED; } } else { throw new ExtensionManagerException('Could not retrieve extension hash file from remote server.', 1342635016); } } return $updateNecessity; }
/** * Shows all versions of a specific extension * * @param string $extensionKey * @return void */ public function showAllVersionsAction($extensionKey) { $currentVersion = $this->extensionRepository->findOneByCurrentVersionByExtensionKey($extensionKey); $extensions = $this->extensionRepository->findByExtensionKeyOrderedByVersion($extensionKey); $this->view->assignMultiple(array('extensionKey' => $extensionKey, 'currentVersion' => $currentVersion, 'extensions' => $extensions)); }
/** * Shows all versions of a specific extension * * @param string $extensionKey */ public function showAllVersionsAction($extensionKey) { $extensions = $this->extensionRepository->findByExtensionKeyOrderedByVersion($extensionKey); $this->view->assign('extensions', $extensions)->assign('extensionKey', $extensionKey); }
/** * Get the latest compatible version of an extension that * fulfills the given dependency from TER * * @param Dependency $dependency * @return Extension */ protected function getLatestCompatibleExtensionByIntegerVersionDependency(Dependency $dependency) { $versions = $this->getLowestAndHighestIntegerVersions($dependency); $compatibleDataSets = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion($dependency->getIdentifier(), $versions['lowestIntegerVersion'], $versions['highestIntegerVersion']); return $compatibleDataSets->getFirst(); }