267ef3414036a06d77c5eec19270672b1f42c143
[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 if (Bootstrap::usesComposerClassLoading()) {
109 $this->settings['composerMode'] = true;
110 }
111 }
112
113 /**
114 * Set up the doc header properly here
115 *
116 * @param ViewInterface $view
117 * @return void
118 */
119 protected function initializeView(ViewInterface $view)
120 {
121 if ($view instanceof BackendTemplateView) {
122 /** @var BackendTemplateView $view */
123 parent::initializeView($view);
124 $this->generateMenu();
125 $this->registerDocheaderButtons();
126 }
127 }
128
129 /**
130 * Adds an information about composer mode
131 */
132 protected function addComposerModeNotification()
133 {
134 if (Bootstrap::usesComposerClassLoading()) {
135 $this->addFlashMessage(
136 LocalizationUtility::translate(
137 'composerMode.message',
138 'extensionmanager'
139 ),
140 LocalizationUtility::translate(
141 'composerMode.title',
142 'extensionmanager'
143 ),
144 FlashMessage::WARNING
145 );
146 }
147 }
148
149 /**
150 * Shows list of extensions present in the system
151 *
152 * @return void
153 */
154 public function indexAction()
155 {
156 $this->addComposerModeNotification();
157 $availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensionsWithAdditionalInformation();
158 ksort($availableAndInstalledExtensions);
159 $this->view->assign('extensions', $availableAndInstalledExtensions);
160 $this->handleTriggerArguments();
161 }
162
163 /**
164 * Shows a list of unresolved dependency errors with the possibility to bypass the dependency check
165 *
166 * @param string $extensionKey
167 * @throws ExtensionManagerException
168 * @return void
169 */
170 public function unresolvedDependenciesAction($extensionKey)
171 {
172 $availableExtensions = $this->listUtility->getAvailableExtensions();
173 if (isset($availableExtensions[$extensionKey])) {
174 $extensionArray = $this->listUtility->enrichExtensionsWithEmConfAndTerInformation(
175 array(
176 $extensionKey => $availableExtensions[$extensionKey]
177 )
178 );
179 /** @var ExtensionModelUtility $extensionModelUtility */
180 $extensionModelUtility = $this->objectManager->get(ExtensionModelUtility::class);
181 $extension = $extensionModelUtility->mapExtensionArrayToModel($extensionArray[$extensionKey]);
182 } else {
183 throw new ExtensionManagerException('Extension ' . $extensionKey . ' is not available', 1402421007);
184 }
185 $this->dependencyUtility->checkDependencies($extension);
186 $this->view->assign('extension', $extension);
187 $this->view->assign('unresolvedDependencies', $this->dependencyUtility->getDependencyErrors());
188 }
189
190 /**
191 * Shows extensions from TER
192 * Either all extensions or depending on a search param
193 *
194 * @param string $search
195 * @return void
196 */
197 public function terAction($search = '')
198 {
199 $this->addComposerModeNotification();
200 $search = trim($search);
201 if (!empty($search)) {
202 $extensions = $this->extensionRepository->findByTitleOrAuthorNameOrExtensionKey($search);
203 } else {
204 $extensions = $this->extensionRepository->findAll();
205 }
206 $availableAndInstalledExtensions = $this->listUtility->getAvailableAndInstalledExtensions($this->listUtility->getAvailableExtensions());
207 $this->view->assign('extensions', $extensions)
208 ->assign('search', $search)
209 ->assign('availableAndInstalled', $availableAndInstalledExtensions);
210 }
211
212 /**
213 * Action for listing all possible distributions
214 *
215 * @param bool $showUnsuitableDistributions
216 * @return void
217 */
218 public function distributionsAction($showUnsuitableDistributions = false)
219 {
220 $this->addComposerModeNotification();
221 $importExportInstalled = ExtensionManagementUtility::isLoaded('impexp');
222 if ($importExportInstalled) {
223 try {
224 /** @var $repositoryHelper Helper */
225 $repositoryHelper = $this->objectManager->get(Helper::class);
226 // Check if a TER update has been done at all, if not, fetch it directly
227 // Repository needs an update, but not because of the extension hash has changed
228 $isExtListUpdateNecessary = $repositoryHelper->isExtListUpdateNecessary();
229 if ($isExtListUpdateNecessary > 0 && ($isExtListUpdateNecessary & $repositoryHelper::PROBLEM_EXTENSION_HASH_CHANGED) === 0) {
230 $repositoryHelper->updateExtList();
231 }
232 } catch (ExtensionManagerException $e) {
233 $this->addFlashMessage($e->getMessage(), $e->getCode(), FlashMessage::ERROR);
234 }
235
236 $officialDistributions = $this->extensionRepository->findAllOfficialDistributions();
237 $communityDistributions = $this->extensionRepository->findAllCommunityDistributions();
238
239 if (!$showUnsuitableDistributions) {
240 $suitableOfficialDistributions = $this->dependencyUtility->getExtensionsSuitableForTypo3Version($officialDistributions);
241 $this->view->assign('officialDistributions', $suitableOfficialDistributions);
242 $suitableCommunityDistributions = $this->dependencyUtility->getExtensionsSuitableForTypo3Version($communityDistributions);
243 $this->view->assign('communityDistributions', $suitableCommunityDistributions);
244 } else {
245 $this->view->assign('officialDistributions', $officialDistributions);
246 $this->view->assign('communityDistributions', $communityDistributions);
247 }
248 }
249 $this->view->assign('enableDistributionsView', $importExportInstalled);
250 $this->view->assign('showUnsuitableDistributions', $showUnsuitableDistributions);
251 }
252
253 /**
254 * Shows all versions of a specific extension
255 *
256 * @param string $extensionKey
257 * @return void
258 */
259 public function showAllVersionsAction($extensionKey)
260 {
261 $currentVersion = $this->extensionRepository->findOneByCurrentVersionByExtensionKey($extensionKey);
262 $extensions = $this->extensionRepository->findByExtensionKeyOrderedByVersion($extensionKey);
263
264 $this->view->assignMultiple(
265 array(
266 'extensionKey' => $extensionKey,
267 'currentVersion' => $currentVersion,
268 'extensions' => $extensions
269 )
270 );
271 }
272
273 /**
274 * Registers the Icons into the docheader
275 *
276 * @return void
277 * @throws \InvalidArgumentException
278 */
279 protected function registerDocheaderButtons()
280 {
281 if ($this->actionMethodName === 'distributionsAction') {
282 return;
283 }
284
285 /** @var ButtonBar $buttonBar */
286 $buttonBar = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar();
287 $uriBuilder = $this->controllerContext->getUriBuilder();
288
289 if ($this->actionMethodName === 'showAllVersionsAction') {
290 $uri = $uriBuilder->reset()->uriFor('ter', [], 'List');
291 $title = $this->translate('extConfTemplate.backToList');
292 $icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-view-go-back', Icon::SIZE_SMALL);
293 $classes = '';
294 } else {
295 $uri = $uriBuilder->reset()->uriFor('form', [], 'UploadExtensionFile');
296 $title = $this->translate('extensionList.uploadExtension');
297 $icon = $this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-edit-upload', Icon::SIZE_SMALL);
298 $classes = 't3js-upload';
299 }
300 $button = $buttonBar->makeLinkButton()
301 ->setHref($uri)
302 ->setTitle($title)
303 ->setClasses($classes)
304 ->setIcon($icon);
305 $buttonBar->addButton($button, ButtonBar::BUTTON_POSITION_LEFT);
306 }
307 }