[TASK] Use BE Routing / PSR-7 instead of BackendUtility::getModuleUrl
[Packages/TYPO3.CMS.git] / typo3 / sysext / opendocs / Classes / Backend / ToolbarItems / OpendocsToolbarItem.php
1 <?php
2 namespace TYPO3\CMS\Opendocs\Backend\ToolbarItems;
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\Toolbar\ToolbarItemInterface;
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
21 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Fluid\View\StandaloneView;
24
25 /**
26 * Main functionality to render a list of all open documents in the top bar of the TYPO3 Backend
27 *
28 * This class also contains hooks and AJAX calls related to the toolbar item dynamic updating processing
29 */
30 class OpendocsToolbarItem implements ToolbarItemInterface
31 {
32 /**
33 * @var array
34 */
35 protected $openDocs = [];
36
37 /**
38 * @var array
39 */
40 protected $recentDocs = [];
41
42 /**
43 * Constructor
44 */
45 public function __construct()
46 {
47 $this->loadDocsFromUserSession();
48 }
49
50 /**
51 * Checks whether the user has access to this toolbar item
52 *
53 * @return bool TRUE if user has access, FALSE if not
54 */
55 public function checkAccess()
56 {
57 $conf = $this->getBackendUser()->getTSConfig('backendToolbarItem.tx_opendocs.disabled');
58 return (int)$conf['value'] !== 1;
59 }
60
61 /**
62 * Loads the opened and recently opened documents from the user
63 */
64 public function loadDocsFromUserSession()
65 {
66 $backendUser = $this->getBackendUser();
67 $openDocs = $backendUser->getModuleData('FormEngine', 'ses');
68 if ($openDocs !== null) {
69 list($this->openDocs, ) = $openDocs;
70 }
71 $this->recentDocs = $backendUser->getModuleData('opendocs::recent') ?: [];
72 }
73
74 /**
75 * Render toolbar icon via Fluid
76 *
77 * @return string HTML
78 */
79 public function getItem()
80 {
81 $view = $this->getFluidTemplateObject('ToolbarItem.html');
82 $view->assign('numDocs', count($this->openDocs));
83 return $view->render();
84 }
85
86 /**
87 * Render drop down via Fluid
88 *
89 * @return string HTML
90 */
91 public function getDropDown()
92 {
93 $view = $this->getFluidTemplateObject('DropDown.html');
94 $view->assignMultiple([
95 'openDocuments' => $this->getMenuEntries($this->openDocs),
96 // If there are "recent documents" in the list, add them
97 'recentDocuments' => $this->getMenuEntries($this->recentDocs)
98 ]);
99 return $view->render();
100 }
101
102 /**
103 * Get menu entries for all eligible records
104 *
105 * @param array $documents
106 * @return array
107 */
108 protected function getMenuEntries(array $documents): array
109 {
110 $entries = [];
111 foreach ($documents as $md5sum => $document) {
112 $menuEntry = $this->getMenuEntry($document, $md5sum);
113 if (is_array($menuEntry)) {
114 $entries[] = $menuEntry;
115 }
116 }
117 return $entries;
118 }
119
120 /**
121 * Returns the data for a recent or open document
122 *
123 * @param array $document
124 * @param string $md5sum
125 * @return array The data of a recent or closed document, or null if no record was found (e.g. deleted)
126 */
127 protected function getMenuEntry($document, $md5sum)
128 {
129 $table = $document[3]['table'];
130 $uid = $document[3]['uid'];
131 $record = BackendUtility::getRecordWSOL($table, $uid);
132 if (!is_array($record)) {
133 // Record seems to be deleted
134 return null;
135 }
136 $result = [];
137 $result['table'] = $table;
138 $result['record'] = $record;
139 $label = htmlspecialchars(strip_tags(htmlspecialchars_decode($document[0])));
140 $result['label'] = $label;
141 /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
142 $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
143 $link = (string)$uriBuilder->buildUriFromRoute('record_edit') . '&' . $document[2];
144 $pageId = (int)$document[3]['uid'];
145 if ($document[3]['table'] !== 'pages') {
146 $pageId = (int)$document[3]['pid'];
147 }
148 $onClickCode = 'jump(' . GeneralUtility::quoteJSvalue($link) . ', \'web_list\', \'web\', ' . $pageId . '); TYPO3.OpendocsMenu.toggleMenu(); return false;';
149 $result['onClickCode'] = $onClickCode;
150 $result['md5sum'] = $md5sum;
151 return $result;
152 }
153
154 /**
155 * No additional attributes
156 *
157 * @return string List item HTML attibutes
158 */
159 public function getAdditionalAttributes()
160 {
161 return [];
162 }
163
164 /**
165 * This item has a drop down
166 *
167 * @return bool
168 */
169 public function hasDropDown()
170 {
171 return true;
172 }
173
174 /*******************
175 *** HOOKS ***
176 *******************/
177 /**
178 * Called as a hook in \TYPO3\CMS\Backend\Utility\BackendUtility::getUpdateSignalCode, calls a JS function to change
179 * the number of opened documents
180 *
181 * @param array $params
182 */
183 public function updateNumberOfOpenDocsHook(&$params)
184 {
185 $params['JScode'] = '
186 if (top && top.TYPO3.OpendocsMenu) {
187 top.TYPO3.OpendocsMenu.updateMenu();
188 }
189 ';
190 }
191
192 /******************
193 *** AJAX CALLS ***
194 ******************/
195 /**
196 * Closes a document in the session and
197 *
198 * @param ServerRequestInterface $request
199 * @param ResponseInterface $response
200 * @return ResponseInterface
201 */
202 public function closeDocument(ServerRequestInterface $request, ResponseInterface $response)
203 {
204 $md5sum = isset($request->getParsedBody()['md5sum']) ? $request->getParsedBody()['md5sum'] : $request->getQueryParams()['md5sum'];
205 if ($md5sum && isset($this->openDocs[$md5sum])) {
206 $backendUser = $this->getBackendUser();
207 // Add the document to be closed to the recent documents
208 $this->recentDocs = array_merge([$md5sum => $this->openDocs[$md5sum]], $this->recentDocs);
209 // Allow a maximum of 8 recent documents
210 if (count($this->recentDocs) > 8) {
211 $this->recentDocs = array_slice($this->recentDocs, 0, 8);
212 }
213 // Remove it from the list of the open documents, and store the status
214 unset($this->openDocs[$md5sum]);
215 list(, $docDat) = $backendUser->getModuleData('FormEngine', 'ses');
216 $backendUser->pushModuleData('FormEngine', [$this->openDocs, $docDat]);
217 $backendUser->pushModuleData('opendocs::recent', $this->recentDocs);
218 }
219 return $this->renderMenu($request, $response);
220 }
221
222 /**
223 * Renders the menu so that it can be returned as response to an AJAX call
224 *
225 * @param ServerRequestInterface $request
226 * @param ResponseInterface $response
227 * @return ResponseInterface
228 */
229 public function renderMenu(ServerRequestInterface $request, ResponseInterface $response)
230 {
231 $response->getBody()->write($this->getDropDown());
232 return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
233 }
234
235 /**
236 * Position relative to others
237 *
238 * @return int
239 */
240 public function getIndex()
241 {
242 return 30;
243 }
244
245 /**
246 * Returns the current BE user.
247 *
248 * @return BackendUserAuthentication
249 */
250 protected function getBackendUser()
251 {
252 return $GLOBALS['BE_USER'];
253 }
254
255 /**
256 * Returns a new standalone view, shorthand function
257 *
258 * @param string $filename Which templateFile should be used.
259 * @return StandaloneView
260 */
261 protected function getFluidTemplateObject(string $filename): StandaloneView
262 {
263 $view = GeneralUtility::makeInstance(StandaloneView::class);
264 $view->setLayoutRootPaths(['EXT:opendocs/Resources/Private/Layouts']);
265 $view->setPartialRootPaths([
266 'EXT:backend/Resources/Private/Partials/ToolbarItems',
267 'EXT:opendocs/Resources/Private/Partials/ToolbarItems'
268 ]);
269 $view->setTemplateRootPaths(['EXT:opendocs/Resources/Private/Templates/ToolbarItems']);
270
271 $view->setTemplate($filename);
272
273 $view->getRequest()->setControllerExtensionName('Opendocs');
274 return $view;
275 }
276 }