[BUGFIX] Select suitable distribution version in em
[Packages/TYPO3.CMS.git] / typo3 / sysext / extensionmanager / Classes / Controller / ListController.php
1 <?php
2 namespace TYPO3\CMS\Extensionmanager\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
18 use TYPO3\CMS\Backend\View\BackendTemplateView;
19 use TYPO3\CMS\Core\Core\Bootstrap;
20 use TYPO3\CMS\Core\Imaging\Icon;
21 use TYPO3\CMS\Core\Messaging\FlashMessage;
22 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
23 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
24 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
25 use TYPO3\CMS\Extensionmanager\Exception\ExtensionManagerException;
26 use TYPO3\CMS\Extensionmanager\Utility\ExtensionModelUtility;
27 use TYPO3\CMS\Extensionmanager\Utility\Repository\Helper;
28
29 /**
30 * Controller for extension listings (TER or local extensions)
31 */
32 class ListController extends AbstractModuleController
33 {
34 /**
35 * @var \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository
36 */
37 protected $extensionRepository;
38
39 /**
40 * @var \TYPO3\CMS\Extensionmanager\Utility\ListUtility
41 */
42 protected $listUtility;
43
44 /**
45 * @var \TYPO3\CMS\Core\Page\PageRenderer
46 */
47 protected $pageRenderer;
48
49 /**
50 * @var \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility
51 */
52 protected $dependencyUtility;
53
54 /**
55 * @var \TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility
56 */
57 protected $configurationUtility;
58
59 /**
60 * @param \TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository
61 */
62 public function injectExtensionRepository(\TYPO3\CMS\Extensionmanager\Domain\Repository\ExtensionRepository $extensionRepository)
63 {
64 $this->extensionRepository = $extensionRepository;
65 }
66
67 /**
68 * @param \TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility
69 */
70 public function injectListUtility(\TYPO3\CMS\Extensionmanager\Utility\ListUtility $listUtility)
71 {
72 $this->listUtility = $listUtility;
73 }
74
75 /**
76 * @param \TYPO3\CMS\Core\Page\PageRenderer $pageRenderer
77 */
78 public function injectPageRenderer(\TYPO3\CMS\Core\Page\PageRenderer $pageRenderer)
79 {
80 $this->pageRenderer = $pageRenderer;
81 }
82
83 /**
84 * @param \TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility
85 */
86 public function injectDependencyUtility(\TYPO3\CMS\Extensionmanager\Utility\DependencyUtility $dependencyUtility)
87 {
88 $this->dependencyUtility = $dependencyUtility;
89 }
90
91 /**
92 * @param \TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility $configurationUtility
93 */
94 public function injectConfigurationUtility(\TYPO3\CMS\Extensionmanager\Utility\ConfigurationUtility $configurationUtility)
95 {
96 $this->configurationUtility = $configurationUtility;
97 }
98
99 /**
100 * Add the needed JavaScript files for all actions
101 */
102 public function initializeAction()
103 {
104 $this->pageRenderer->addInlineLanguageLabelFile('EXT:extensionmanager/Resources/Private/Language/locallang.xlf');
105 if ($this->configurationUtility->getCurrentConfiguration('extensionmanager')['offlineMode']['value']) {
106 $this->settings['offlineMode'] = true;
107 }
108 }
109
110 /**
111 * Set up the doc header properly here
112 *
113 * @param ViewInterface $view
114 */
115 protected function initializeView(ViewInterface $view)
116 {
117 if ($view instanceof BackendTemplateView) {
118 /** @var BackendTemplateView $view */
119 parent::initializeView($view);
120 $this->generateMenu();
121 $this->registerDocheaderButtons();
122 }
123 }
124
125 /**
126 * Adds an information about composer mode
127 */
128 protected function addComposerModeNotification()
129 {
130 if (Bootstrap::usesComposerClassLoading()) {
131 $this->addFlashMessage(
132 LocalizationUtility::translate(
133 'composerMode.message',
134 'extensionmanager'
135 ),
136 LocalizationUtility::translate(
137 'composerMode.title',
138 'extensionmanager'
139 ),
140 FlashMessage::INFO
141 );
142 }
143 }
144
145 /**
146 * Shows list of extensions present in the system
147 */
148 public function indexAction()
149 {
150 $this->addComposerModeNotification();
151 $availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensionsWithAdditionalInformation();
152 ksort($availableAndInstalledExtensions);
153 $this->view->assign('extensions', $availableAndInstalledExtensions);
154 $this->handleTriggerArguments();
155 }
156
157 /**
158 * Shows a list of unresolved dependency errors with the possibility to bypass the dependency check
159 *
160 * @param string $extensionKey
161 * @throws ExtensionManagerException
162 */
163 public function unresolvedDependenciesAction($extensionKey)
164 {
165 $availableExtensions = $this->listUtility->getAvailableExtensions();
166 if (isset($availableExtensions[$extensionKey])) {
167 $extensionArray = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation(
168 [
169 $extensionKey => $availableExtensions[$extensionKey]
170 ]
171 );
172 /** @var ExtensionModelUtility $extensionModelUtility */
173 $extensionModelUtility = $this->objectManager->get(ExtensionModelUtility::class);
174 $extension = $extensionModelUtility->mapExtensionArrayToModel($extensionArray[$extensionKey]);
175 } else {
176 throw new ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1402421007);
177 }
178 $this->dependencyUtility->checkDependencies($extension);
179 $this->view->assign('extension', $extension);
180 $this->view->assign('unresolvedDependencies', $this->dependencyUtility->getDependencyErrors());
181 }
182
183 /**
184 * Shows extensions from TER
185 * Either all extensions or depending on a search param
186 *
187 * @param string $search
188 */
189 public function terAction($search = '')
190 {
191 $this->addComposerModeNotification();
192 $search = trim($search);
193 if (!empty($search)) {
194 $extensions = $this->extensionRepository->findByTitleOrAuthorNameOrExtensionKey($search);
195 } else {
196 $extensions = $this->extensionRepository->findAll();
197 }
198 $availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensions($this->listUtility->getAvailableExtensions());
199 $this->view->assign('extensions', $extensions)
200 ->assign('search', $search)
201 ->assign('availableAndInstalled', $availableAndInstalledExtensions);
202 }
203
204 /**
205 * Action for listing all possible distributions
206 *
207 * @param bool $showUnsuitableDistributions
208 */
209 public function distributionsAction($showUnsuitableDistributions = false)
210 {
211 $this->addComposerModeNotification();
212 $importExportInstalled = ExtensionManagementUtility::isLoaded('impexp');
213 if ($importExportInstalled) {
214 try {
215 /** @var $repositoryHelper Helper */
216 $repositoryHelper = $this->objectManager->get(Helper::class);
217 // Check if a TER update has been done at all, if not, fetch it directly
218 // Repository needs an update, but not because of the extension hash has changed
219 $isExtListUpdateNecessary = $repositoryHelper->isExtListUpdateNecessary();
220 if ($isExtListUpdateNecessary > 0 && ($isExtListUpdateNecessary & $repositoryHelper::PROBLEM_EXTENSION_HASH_CHANGED) === 0) {
221 $repositoryHelper->updateExtList();
222 }
223 } catch (ExtensionManagerException $e) {
224 $this->addFlashMessage($e->getMessage(), $e->getCode(), FlashMessage::ERROR);
225 }
226
227 $officialDistributions = $this->extensionRepository->findAllOfficialDistributions();
228 $communityDistributions = $this->extensionRepository->findAllCommunityDistributions();
229
230 $officialDistributions = $this->dependencyUtility->filterYoungestVersionOfExtensionList($officialDistributions->toArray(), $showUnsuitableDistributions);
231 $communityDistributions = $this->dependencyUtility->filterYoungestVersionOfExtensionList($communityDistributions->toArray(), $showUnsuitableDistributions);
232
233 $this->view->assign('officialDistributions', $officialDistributions);
234 $this->view->assign('communityDistributions', $communityDistributions);
235 }
236 $this->view->assign('enableDistributionsView', $importExportInstalled);
237 $this->view->assign('showUnsuitableDistributions', $showUnsuitableDistributions);
238 }
239
240 /**
241 * Shows all versions of a specific extension
242 *
243 * @param string $extensionKey
244 */
245 public function showAllVersionsAction($extensionKey)
246 {
247 $currentVersion = $this->extensionRepository->findOneByCurrentVersionByExtensionKey($extensionKey);
248 $extensions = $this->extensionRepository->findByExtensionKeyOrderedByVersion($extensionKey);
249
250 $this->view->assignMultiple(
251 [
252 'extensionKey' => $extensionKey,
253 'currentVersion' => $currentVersion,
254 'extensions' => $extensions
255 ]
256 );
257 }
258
259 /**
260 * Registers the Icons into the docheader
261 *
262 * @throws \InvalidArgumentException
263 */
264 protected function registerDocheaderButtons()
265 {
266 if (Bootstrap::usesComposerClassLoading()) {
267 return;
268 }
269
270 if (!in_array($this->actionMethodName, ['indexAction', 'terAction', 'showAllVersionsAction'], true)) {
271 return;
272 }
273
274 /** @var ButtonBar $buttonBar */
275 $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
276 $uriBuilder = $this->controllerContext->getUriBuilder();
277
278 if ($this->actionMethodName === 'showAllVersionsAction') {
279 $uri = $uriBuilder->reset()->uriFor('ter', [], 'List');
280 $title = $this->translate('extConfTemplate.backToList');
281 $icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL);
282 $classes = '';
283 } else {
284 $uri = $uriBuilder->reset()->uriFor('form', [], 'UploadExtensionFile');
285 $title = $this->translate('extensionList.uploadExtension');
286 $icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-edit-upload', Icon::SIZE_SMALL);
287 $classes = 't3js-upload';
288 }
289 $button = $buttonBar->makeLinkButton()
290 ->setHref($uri)
291 ->setTitle($title)
292 ->setClasses($classes)
293 ->setIcon($icon);
294 $buttonBar->addButton($button, ButtonBar::BUTTON_POSITION_LEFT);
295 }
296 }