cd623ad3a9d07b5eceaab630ccbd2d2374dee57c
[Packages/TYPO3.CMS.git] / typo3 / sysext / documentation / Classes / Controller / DocumentController.php
1 <?php
2 namespace TYPO3\CMS\Documentation\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 Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\View\BackendTemplateView;
20 use TYPO3\CMS\Core\Http\JsonResponse;
21 use TYPO3\CMS\Core\Localization\LanguageService;
22 use TYPO3\CMS\Core\Messaging\FlashMessage;
23 use TYPO3\CMS\Core\Page\PageRenderer;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25 use TYPO3\CMS\Documentation\Domain\Repository\DocumentRepository;
26 use TYPO3\CMS\Documentation\Service\DocumentationService;
27 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
28 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
29 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
30 use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
31 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
32
33 /**
34 * Main controller of the Documentation module.
35 */
36 class DocumentController extends ActionController
37 {
38 /**
39 * @var DocumentRepository
40 */
41 protected $documentRepository;
42
43 /**
44 * @var DocumentationService
45 */
46 protected $documentationService;
47
48 /**
49 * @var Dispatcher
50 */
51 protected $signalSlotDispatcher;
52
53 /**
54 * Backend Template Container
55 *
56 * @var BackendTemplateView
57 */
58 protected $defaultViewObjectName = BackendTemplateView::class;
59
60 /**
61 * BackendTemplateContainer
62 *
63 * @var BackendTemplateView
64 */
65 protected $view;
66
67 /**
68 * Set up the doc header properly here
69 *
70 * @param ViewInterface $view
71 */
72 protected function initializeView(ViewInterface $view)
73 {
74 if ($view instanceof BackendTemplateView) {
75 /** @var BackendTemplateView $view */
76 parent::initializeView($view);
77 $view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation([]);
78 $uriBuilder = $this->objectManager->get(UriBuilder::class);
79 $uriBuilder->setRequest($this->request);
80
81 $this->view->getModuleTemplate()->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Documentation/Main');
82 $menu = $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->makeMenu();
83 $menu->setIdentifier('DocumentationModuleMenu');
84
85 $isListActive = $this->request->getControllerActionName() === 'list' ? true : false;
86 $uri = $uriBuilder->reset()->uriFor('list', [], 'Document');
87 $listMenuItem = $menu->makeMenuItem()
88 ->setTitle($this->getLanguageService()
89 ->sL('LLL:EXT:documentation/Resources/Private/Language/locallang.xlf:showDocumentation'))
90 ->setHref($uri)
91 ->setActive($isListActive);
92 $menu->addMenuItem($listMenuItem);
93
94 if ($this->getBackendUser()->isAdmin()) {
95 $isDownloadActive = $this->request->getControllerActionName() ===
96 'download' ? true : false;
97 $uri =
98 $uriBuilder->reset()->uriFor('download', [], 'Document');
99 $downloadMenuItem = $menu->makeMenuItem()
100 ->setTitle($this->getLanguageService()
101 ->sL('LLL:EXT:documentation/Resources/Private/Language/locallang.xlf:downloadDocumentation'))
102 ->setHref($uri)
103 ->setActive($isDownloadActive);
104 $menu->addMenuItem($downloadMenuItem);
105 }
106
107 $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
108 $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
109 }
110 }
111
112 /**
113 * @param DocumentRepository $documentRepository
114 */
115 public function injectDocumentRepository(DocumentRepository $documentRepository)
116 {
117 $this->documentRepository = $documentRepository;
118 }
119
120 /**
121 * @param DocumentationService $documentationService
122 */
123 public function injectDocumentationService(DocumentationService $documentationService)
124 {
125 $this->documentationService = $documentationService;
126 }
127
128 /**
129 * @param Dispatcher $signalSlotDispatcher
130 */
131 public function injectSignalSlotDispatcher(Dispatcher $signalSlotDispatcher)
132 {
133 $this->signalSlotDispatcher = $signalSlotDispatcher;
134 }
135
136 /**
137 * Lists the available documents.
138 */
139 public function listAction()
140 {
141 $this->view->getModuleTemplate()->getDocHeaderComponent()->setMetaInformation([]);
142
143 $documents = $this->getDocuments();
144
145 // Filter documents to be shown for current user
146 $userTsConfig = $this->getBackendUser()->getTSConfig();
147 $hideDocuments = GeneralUtility::trimExplode(',', $userTsConfig['mod.']['help_DocumentationDocumentation.']['documents.']['hide'] ?? '', true);
148 if (!empty($hideDocuments)) {
149 $documents = array_diff_key($documents, array_flip($hideDocuments));
150 }
151 $showDocuments = GeneralUtility::trimExplode(',', $userTsConfig['mod.']['help_DocumentationDocumentation.']['documents.']['show'] ?? '', true);
152 if (!empty($showDocuments)) {
153 $documents = array_intersect_key($documents, array_flip($showDocuments));
154 }
155
156 $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
157 $pageRenderer->addInlineLanguageLabelFile('EXT:documentation/Resources/Private/Language/locallang.xlf');
158 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Documentation/Main');
159
160 $this->view->assign('documents', $documents);
161 }
162
163 /**
164 * Delete documentation with given packageKey
165 *
166 * @param ServerRequestInterface $request
167 * @return ResponseInterface
168 */
169 public function deleteAction(ServerRequestInterface $request): ResponseInterface
170 {
171 $basePath = 'typo3conf/Documentation/';
172 $packageKey = $request->getParsedBody();
173 $isDirDeleted = GeneralUtility::rmdir(PATH_site . $basePath . $packageKey['documentationKey'], true);
174 if (!$isDirDeleted) {
175 $this->addFlashMessage(LocalizationUtility::translate('deleteFailed', 'Documentation'), '', FlashMessage::ERROR);
176 }
177 return new JsonResponse([$isDirDeleted]);
178 }
179
180 /**
181 * Returns available documents.
182 *
183 * @return \TYPO3\CMS\Documentation\Domain\Model\Document[]
184 * @api
185 */
186 public function getDocuments()
187 {
188 $language = $this->getBackendUser()->uc['lang'] ?: 'default';
189 $documents = $this->documentRepository->findByLanguage($language);
190
191 $documents = $this->emitAfterInitializeDocumentsSignal($language, $documents);
192
193 return $documents;
194 }
195
196 /**
197 * Emits a signal after the documents are initialized
198 *
199 * @param string $language
200 * @param \TYPO3\CMS\Documentation\Domain\Model\Document[] $documents
201 * @return \TYPO3\CMS\Documentation\Domain\Model\Document[]
202 */
203 protected function emitAfterInitializeDocumentsSignal($language, array $documents)
204 {
205 $this->signalSlotDispatcher->dispatch(
206 __CLASS__,
207 'afterInitializeDocuments',
208 [
209 $language,
210 &$documents,
211 ]
212 );
213 return $documents;
214 }
215
216 /**
217 * Shows documents to be downloaded/fetched from a remote location.
218 */
219 public function downloadAction()
220 {
221 // This action is reserved for admin users. Redirect to default view if not.
222 if (!$this->getBackendUser()->isAdmin()) {
223 $this->redirect('list');
224 }
225
226 // Retrieve the list of official documents
227 $documents = $this->documentationService->getOfficialDocuments();
228
229 // Merge with the list of local extensions
230 $extensions = $this->documentationService->getLocalExtensions();
231 $allDocuments = array_merge($documents, $extensions);
232
233 $this->view->assign('documents', $allDocuments);
234 }
235
236 /**
237 * Fetches a document from a remote URL.
238 *
239 * @param string $url
240 * @param string $key
241 * @param string $version
242 */
243 public function fetchAction($url, $key, $version = null)
244 {
245 // This action is reserved for admin users. Redirect to default view if not.
246 if (!$this->getBackendUser()->isAdmin()) {
247 $this->redirect('list');
248 }
249
250 $language = $this->getBackendUser()->uc['lang'] ?: 'default';
251 try {
252 $result = $this->documentationService->fetchNearestDocument($url, $key, $version ?: 'latest', $language);
253 if ($result) {
254 $this->addFlashMessage(
255 LocalizationUtility::translate(
256 'downloadSucceeded',
257 'documentation'
258 ),
259 '',
260 FlashMessage::OK
261 );
262 } else {
263 $this->addFlashMessage(
264 LocalizationUtility::translate(
265 'downloadFailedNoArchive',
266 'documentation'
267 ),
268 LocalizationUtility::translate(
269 'downloadFailed',
270 'documentation'
271 ),
272 FlashMessage::ERROR
273 );
274 }
275 } catch (\Exception $e) {
276 $this->addFlashMessage(
277 LocalizationUtility::translate(
278 'downloadFailedDetails',
279 'documentation',
280 [
281 $key,
282 $e->getMessage(),
283 $e->getCode()
284 ]
285 ),
286 LocalizationUtility::translate(
287 'downloadFailed',
288 'documentation'
289 ),
290 FlashMessage::ERROR
291 );
292 }
293 $this->redirect('download');
294 }
295
296 /**
297 * Get backend user
298 *
299 * @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
300 */
301 protected function getBackendUser()
302 {
303 return $GLOBALS['BE_USER'];
304 }
305
306 /**
307 * Returns the LanguageService
308 *
309 * @return LanguageService
310 */
311 protected function getLanguageService()
312 {
313 return $GLOBALS['LANG'];
314 }
315 }