‪TYPO3CMS  ‪main
DownloadController.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\Http\Message\ResponseInterface;
30 use TYPO3\CMS\Extensionmanager\Service\ExtensionManagementService;
32 
37 class DownloadController extends AbstractController
38 {
39  protected string $defaultViewObjectName = JsonView::class;
40 
44  protected $view;
45 
46  public function __construct(
47  protected readonly ExtensionRepository $extensionRepository,
48  protected readonly ExtensionManagementService $managementService,
49  protected readonly ExtensionConfiguration $extensionConfiguration,
50  ) {}
51 
55  public function checkDependenciesAction(Extension $extension): ResponseInterface
56  {
57  $message = '';
58  $title = '';
59  $hasDependencies = false;
60  $hasErrors = false;
61  $dependencyTypes = null;
62  $configuration = [
63  'value' => [
64  'dependencies' => [],
65  ],
66  ];
67  $isAutomaticInstallationEnabled = (bool)$this->extensionConfiguration->get('extensionmanager', 'automaticInstallation');
68  if (!$isAutomaticInstallationEnabled) {
69  // if automatic installation is deactivated, no dependency check is needed (download only)
70  $action = 'installExtensionWithoutSystemDependencyCheck';
71  } else {
72  $action = 'installFromTer';
73  try {
74  $dependencyTypes = $this->managementService->getAndResolveDependencies($extension);
75  if (!empty($dependencyTypes)) {
76  $hasDependencies = true;
77  $message = '<p>' . $this->translate('downloadExtension.dependencies.headline') . '</p>';
78  foreach ($dependencyTypes as $dependencyType => $dependencies) {
79  $extensions = '';
80  foreach ($dependencies as $extensionKey => $dependency) {
81  if (!isset($configuration['value']['dependencies'][$dependencyType])) {
82  $configuration['value']['dependencies'][$dependencyType] = [];
83  }
84  $configuration['value']['dependencies'][$dependencyType][$extensionKey] = [
85  '_exclude' => [
86  'categoryIndexFromStringOrNumber',
87  ],
88  ];
89  $extensions .= $this->translate(
90  'downloadExtension.dependencies.extensionWithVersion',
91  [
92  $extensionKey, $dependency->getVersion(),
93  ]
94  ) . '<br />';
95  }
96  $message .= $this->translate(
97  'downloadExtension.dependencies.typeHeadline',
98  [
99  $this->translate('downloadExtension.dependencyType.' . $dependencyType),
100  $extensions,
101  ]
102  );
103  }
104  $title = $this->translate('downloadExtension.dependencies.resolveAutomatically');
105  }
106  } catch (\Exception $e) {
107  $hasErrors = true;
108  $title = $this->translate('downloadExtension.dependencies.errorTitle');
109  $message = $e->getMessage();
110  }
111  }
112 
113  ‪$url = $this->uriBuilder->uriFor(
114  $action,
115  ['extension' => $extension->getUid(), 'format' => 'json'],
116  'Download'
117  );
118  $this->view->setConfiguration($configuration);
119  $this->view->assign('value', [
120  'dependencies' => $dependencyTypes,
121  'url' => ‪$url,
122  'message' => $message,
123  'hasErrors' => $hasErrors,
124  'hasDependencies' => $hasDependencies,
125  'title' => $title,
126  ]);
127 
128  return $this->jsonResponse();
129  }
130 
134  protected function initializeInstallFromTerAction()
135  {
136  // @todo: Switch to JsonView
137  $this->defaultViewObjectName = TemplateView::class;
138  }
139 
143  public function installFromTerAction(Extension $extension): ResponseInterface
144  {
145  [$result, $errorMessages] = $this->installFromTer($extension);
146  $isAutomaticInstallationEnabled = (bool)$this->extensionConfiguration->get('extensionmanager', 'automaticInstallation');
147  $this->view->assignMultiple([
148  'result' => $result,
149  'extension' => $extension,
150  'installationTypeLanguageKey' => $isAutomaticInstallationEnabled ? '' : '.downloadOnly',
151  'unresolvedDependencies' => $errorMessages,
152  ]);
153 
154  return $this->htmlResponse();
155  }
156 
160  public function installExtensionWithoutSystemDependencyCheckAction(Extension $extension): ResponseInterface
161  {
162  $this->managementService->setSkipDependencyCheck(true);
163  return (new ForwardResponse('installFromTer'))->withArguments(['extension' => $extension]);
164  }
165 
170  public function installDistributionAction(Extension $extension): ResponseInterface
171  {
173  return (new ForwardResponse('distributions'))->withControllerName('List');
174  }
175  [$result] = $this->installFromTer($extension);
176  if (!$result) {
177  return $this->redirect(
178  'unresolvedDependencies',
179  'List',
180  null,
181  [
182  'extensionKey' => $extension->getExtensionKey(),
183  'returnAction' => ['controller' => 'List', 'action' => 'distributions'],
184  ]
185  );
186  }
187  // FlashMessage that extension is installed
188  $this->addFlashMessage(
190  'distribution.welcome.message',
191  'extensionmanager',
192  [$extension->getExtensionKey()]
193  ) ?? '',
194  ‪LocalizationUtility::translate('distribution.welcome.headline', 'extensionmanager') ?? ''
195  );
196 
197  // Redirect to show action
198  return $this->redirect(
199  'show',
200  'Distribution',
201  null,
202  ['extension' => $extension]
203  );
204  }
205 
212  protected function updateExtensionAction(): ResponseInterface
213  {
214  $extensionKey = $this->request->getArgument('extension');
215  $version = $this->request->getArgument('version');
216  $extension = $this->extensionRepository->findOneByExtensionKeyAndVersion($extensionKey, $version);
217  if (!$extension instanceof Extension) {
218  $extension = $this->extensionRepository->findHighestAvailableVersion($extensionKey);
219  }
221  try {
222  if (in_array($extensionKey, $installedExtensions, true)) {
223  // To resolve new dependencies the extension is installed again
224  $this->managementService->installExtension($extension);
225  } else {
226  $this->managementService->downloadMainExtension($extension);
227  }
228  $this->addFlashMessage(
229  $this->translate('extensionList.updateFlashMessage.body', [$extensionKey]),
230  $this->translate('extensionList.updateFlashMessage.title')
231  );
232  } catch (\Exception $e) {
233  $this->addFlashMessage($e->getMessage(), '', ContextualFeedbackSeverity::ERROR);
234  }
235 
236  return $this->jsonResponse();
237  }
238 
244  protected function updateCommentForUpdatableVersionsAction(): ResponseInterface
245  {
246  $extensionKey = $this->request->getArgument('extension');
247  $versionStart = $this->request->getArgument('integerVersionStart');
248  $versionStop = $this->request->getArgument('integerVersionStop');
249  $updateComments = [];
251  $updatableVersions = $this->extensionRepository->findByVersionRangeAndExtensionKeyOrderedByVersion(
252  $extensionKey,
253  $versionStart,
254  $versionStop,
255  false
256  );
257  $highestPossibleVersion = false;
258 
259  foreach ($updatableVersions as $updatableVersion) {
260  if ($highestPossibleVersion === false) {
261  $highestPossibleVersion = $updatableVersion->getVersion();
262  }
263  $updateComments[$updatableVersion->getVersion()] = $updatableVersion->getUpdateComment();
264  }
265 
266  $this->view->assign('value', [
267  'updateComments' => $updateComments,
268  'url' => $this->uriBuilder->uriFor(
269  'updateExtension',
270  ['extension' => $extensionKey, 'version' => $highestPossibleVersion]
271  ),
272  ]);
273 
274  return $this->jsonResponse();
275  }
276 
290  protected function installFromTer(Extension $extension): array
291  {
292  $result = false;
293  $errorMessages = [];
294  try {
295  $isAutomaticInstallationEnabled = (bool)$this->extensionConfiguration->get('extensionmanager', 'automaticInstallation');
296  $this->managementService->setAutomaticInstallationEnabled($isAutomaticInstallationEnabled);
297  if (($result = $this->managementService->installExtension($extension)) === false) {
298  $errorMessages = $this->managementService->getDependencyErrors();
299  }
300  } catch (ExtensionManagerException $e) {
301  $errorMessages = [
302  $extension->getExtensionKey() => [
303  [
304  'code' => $e->getCode(),
305  'message' => $e->getMessage(),
306  ],
307  ],
308  ];
309  }
310 
311  return [$result, $errorMessages];
312  }
313 }
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\getLoadedExtensionListArray
‪static getLoadedExtensionListArray()
Definition: ExtensionManagementUtility.php:1152
‪TYPO3\CMS\Extbase\Utility\LocalizationUtility
Definition: LocalizationUtility.php:35
‪TYPO3\CMS\Extensionmanager\Domain\Model\Extension
Definition: Extension.php:30
‪TYPO3\CMS\Core\Configuration\ExtensionConfiguration
Definition: ExtensionConfiguration.php:47
‪TYPO3\CMS\Extensionmanager\Controller
Definition: AbstractController.php:18
‪TYPO3\CMS\Extbase\Http\ForwardResponse
Definition: ForwardResponse.php:24
‪TYPO3\CMS\Fluid\View\TemplateView
Definition: TemplateView.php:22
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility\isLoaded
‪static isLoaded(string $key)
Definition: ExtensionManagementUtility.php:55
‪TYPO3\CMS\Core\Utility\ExtensionManagementUtility
Definition: ExtensionManagementUtility.php:32
‪TYPO3\CMS\Core\Type\ContextualFeedbackSeverity
‪ContextualFeedbackSeverity
Definition: ContextualFeedbackSeverity.php:25
‪TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
Definition: ExtensionRepository.php:37
‪TYPO3\CMS\Extbase\Utility\LocalizationUtility\translate
‪static string null translate(string $key, ?string $extensionName=null, array $arguments=null, Locale|string $languageKey=null)
Definition: LocalizationUtility.php:47
‪TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException
Definition: ExtensionManagerException.php:25
‪TYPO3\CMS\Webhooks\Message\$url
‪identifier readonly UriInterface $url
Definition: LoginErrorOccurredMessage.php:36
‪TYPO3\CMS\Extbase\Mvc\View\JsonView
Definition: JsonView.php:29