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