[TASK] Respect alternative web mounts in suggest wizard
[Packages/TYPO3.CMS.git] / typo3 / sysext / recordlist / Classes / Browser / DatabaseBrowser.php
1 <?php
2 namespace TYPO3\CMS\Recordlist\Browser;
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\RecordList\ElementBrowserRecordList;
18 use TYPO3\CMS\Backend\Utility\BackendUtility;
19 use TYPO3\CMS\Core\Imaging\Icon;
20 use TYPO3\CMS\Core\Type\Bitmask\Permission;
21 use TYPO3\CMS\Core\Utility\GeneralUtility;
22 use TYPO3\CMS\Core\Utility\MathUtility;
23 use TYPO3\CMS\Recordlist\Tree\View\ElementBrowserPageTreeView;
24 use TYPO3\CMS\Recordlist\Tree\View\LinkParameterProviderInterface;
25
26 /**
27 * Showing a page tree and allows you to browse for records
28 * @internal This class is a specific LinkBrowser implementation and is not part of the TYPO3's Core API.
29 */
30 class DatabaseBrowser extends AbstractElementBrowser implements ElementBrowserInterface, LinkParameterProviderInterface
31 {
32 /**
33 * When you click a page title/expand icon to see the content of a certain page, this
34 * value will contain the ID of the expanded page.
35 * If the value is NOT set by GET parameter, then it will be restored from the module session data.
36 *
37 * @var int|null
38 */
39 protected $expandPage;
40
41 /**
42 */
43 protected function initialize()
44 {
45 parent::initialize();
46 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Recordlist/BrowseDatabase');
47 }
48
49 /**
50 */
51 protected function initVariables()
52 {
53 parent::initVariables();
54 $this->expandPage = GeneralUtility::_GP('expandPage');
55 }
56
57 /**
58 * Session data for this class can be set from outside with this method.
59 *
60 * @param mixed[] $data Session data array
61 * @return array[] Session data and boolean which indicates that data needs to be stored in session because it's changed
62 */
63 public function processSessionData($data)
64 {
65 if ($this->expandPage !== null) {
66 $data['expandPage'] = $this->expandPage;
67 $store = true;
68 } else {
69 $this->expandPage = (int)$data['expandPage'];
70 $store = false;
71 }
72 return [$data, $store];
73 }
74
75 /**
76 * @return string HTML content
77 */
78 public function render()
79 {
80 $userTsConfig = $this->getBackendUser()->getTSConfig();
81
82 $this->setTemporaryDbMounts();
83 list(, , , $allowedTables) = explode('|', $this->bparams);
84
85 // Making the browsable pagetree:
86 $pageTree = GeneralUtility::makeInstance(ElementBrowserPageTreeView::class);
87 $pageTree->setLinkParameterProvider($this);
88 $pageTree->ext_pArrPages = $allowedTables === 'pages';
89 $pageTree->ext_showNavTitle = (bool)($userTsConfig['options.']['pageTree.']['showNavTitle'] ?? false);
90 $pageTree->ext_showPageId = (bool)($userTsConfig['options.']['pageTree.']['showPageIdWithTitle'] ?? false);
91 $pageTree->ext_showPathAboveMounts = (bool)($userTsConfig['options.']['pageTree.']['showPathAboveMounts'] ?? false);
92 $pageTree->addField('nav_title');
93 $tree = $pageTree->getBrowsableTree();
94
95 $withTree = true;
96 if ($allowedTables !== '' && $allowedTables !== '*') {
97 $tablesArr = GeneralUtility::trimExplode(',', $allowedTables, true);
98 $onlyRootLevel = true;
99 foreach ($tablesArr as $currentTable) {
100 if (isset($GLOBALS['TCA'][$currentTable])) {
101 if (!isset($GLOBALS['TCA'][$currentTable]['ctrl']['rootLevel']) || (int)$GLOBALS['TCA'][$currentTable]['ctrl']['rootLevel'] !== 1) {
102 $onlyRootLevel = false;
103 }
104 }
105 }
106 if ($onlyRootLevel) {
107 $withTree = false;
108 // page to work on is root
109 $this->expandPage = 0;
110 }
111 }
112
113 $renderedRecordList = $this->renderTableRecords($allowedTables);
114
115 $this->initDocumentTemplate();
116 $content = $this->doc->startPage(htmlspecialchars($this->getLanguageService()->getLL('recordSelector')));
117
118 // Putting the parts together, side by side:
119 $markup = [];
120 $markup[] = '<!-- Wrapper table for folder tree / filelist: -->';
121 $markup[] = '<div class="element-browser">';
122 $markup[] = ' <div class="element-browser-panel element-browser-main">';
123 if ($withTree) {
124 $markup[] = ' <div class="element-browser-main-sidebar">';
125 $markup[] = ' <div class="element-browser-body">';
126 $markup[] = ' <h3>' . htmlspecialchars($this->getLanguageService()->getLL('pageTree')) . ':</h3>';
127 $markup[] = ' ' . $this->getTemporaryTreeMountCancelNotice();
128 $markup[] = ' ' . $tree;
129 $markup[] = ' </div>';
130 $markup[] = ' </div>';
131 }
132 $markup[] = ' <div class="element-browser-main-content">';
133 $markup[] = ' <div class="element-browser-body">';
134 $markup[] = ' ' . $this->doc->getFlashMessages();
135 $markup[] = ' ' . $renderedRecordList;
136 $markup[] = ' </div>';
137 $markup[] = ' </div>';
138 $markup[] = ' </div>';
139 $markup[] = '</div>';
140 $content .= implode('', $markup);
141
142 // Ending page, returning content:
143 $content .= $this->doc->endPage();
144 return $this->doc->insertStylesAndJS($content);
145 }
146
147 /**
148 * Check if a temporary tree mount is set and return a cancel button
149 *
150 * @return string HTML code
151 */
152 protected function getTemporaryTreeMountCancelNotice()
153 {
154 if ((int)$this->getBackendUser()->getSessionData('pageTree_temporaryMountPoint') === 0) {
155 return '';
156 }
157 $link = '<p><a href="' . htmlspecialchars(GeneralUtility::linkThisScript(['setTempDBmount' => 0])) . '" class="btn btn-primary">'
158 . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.temporaryDBmount')) . '</a></p>';
159
160 return $link;
161 }
162
163 /**
164 * If the current Backend User has set a temporary DB mount, it is stored to her/his UC.
165 */
166 protected function setTemporaryDbMounts()
167 {
168 $backendUser = $this->getBackendUser();
169
170 // Clear temporary DB mounts
171 $tmpMount = GeneralUtility::_GET('setTempDBmount');
172 if (isset($tmpMount)) {
173 $backendUser->setAndSaveSessionData('pageTree_temporaryMountPoint', (int)$tmpMount);
174 }
175
176 $backendUser->initializeWebmountsForElementBrowser();
177 }
178
179 /**
180 * This lists all content elements for the given list of tables
181 *
182 * @param string $tables Comma separated list of tables. Set to "*" if you want all tables.
183 * @return string HTML code
184 */
185 protected function renderTableRecords($tables)
186 {
187 $backendUser = $this->getBackendUser();
188 if ($this->expandPage === null || $this->expandPage < 0 || !$backendUser->isInWebMount($this->expandPage)) {
189 return '';
190 }
191 // Set array with table names to list:
192 if (trim($tables) === '*') {
193 $tablesArr = array_keys($GLOBALS['TCA']);
194 } else {
195 $tablesArr = GeneralUtility::trimExplode(',', $tables, true);
196 }
197
198 $out = '<h3>' . htmlspecialchars($this->getLanguageService()->getLL('selectRecords')) . ':</h3>';
199 // Create the header, showing the current page for which the listing is.
200 // Includes link to the page itself, if pages are amount allowed tables.
201 $titleLen = (int)$backendUser->uc['titleLen'];
202 $mainPageRecord = BackendUtility::getRecordWSOL('pages', $this->expandPage);
203 if (is_array($mainPageRecord)) {
204 $pText = htmlspecialchars(GeneralUtility::fixed_lgd_cs($mainPageRecord['title'], $titleLen));
205
206 $out .= $this->iconFactory->getIconForRecord('pages', $mainPageRecord, Icon::SIZE_SMALL)->render();
207 if (in_array('pages', $tablesArr, true)) {
208 $out .= '<span data-uid="' . htmlspecialchars($mainPageRecord['uid']) . '" data-table="pages" data-title="' . htmlspecialchars($mainPageRecord['title']) . '" data-icon="">';
209 $out .= '<a href="#" data-close="0">'
210 . $this->iconFactory->getIcon('actions-add', Icon::SIZE_SMALL)->render()
211 . '</a>'
212 . '<a href="#" data-close="1">'
213 . $pText
214 . '</a>';
215 $out .= '</span>';
216 } else {
217 $out .= $pText;
218 }
219 $out .= '<br />';
220 }
221
222 $permsClause = $backendUser->getPagePermsClause(Permission::PAGE_SHOW);
223 $pageInfo = BackendUtility::readPageAccess($this->expandPage, $permsClause);
224
225 /** @var ElementBrowserRecordList $dbList */
226 $dbList = GeneralUtility::makeInstance(ElementBrowserRecordList::class);
227 $dbList->setOverrideUrlParameters($this->getUrlParameters([]));
228 $dbList->thisScript = $this->thisScript;
229 $dbList->thumbs = false;
230 $dbList->setIsEditable(false);
231 $dbList->calcPerms = $backendUser->calcPerms($pageInfo);
232 $dbList->noControlPanels = true;
233 $dbList->clickMenuEnabled = false;
234 $dbList->tableList = implode(',', $tablesArr);
235
236 // a string like "data[pages][79][storage_pid]"
237 list($fieldPointerString) = explode('|', $this->bparams);
238 // parts like: data, pages], 79], storage_pid]
239 $fieldPointerParts = explode('[', $fieldPointerString);
240 $relatingTableName = substr($fieldPointerParts[1], 0, -1);
241 $relatingFieldName = substr($fieldPointerParts[3], 0, -1);
242 if ($relatingTableName && $relatingFieldName) {
243 $dbList->setRelatingTableAndField($relatingTableName, $relatingFieldName);
244 }
245
246 $dbList->start(
247 $this->expandPage,
248 GeneralUtility::_GP('table'),
249 MathUtility::forceIntegerInRange(GeneralUtility::_GP('pointer'), 0, 100000),
250 GeneralUtility::_GP('search_field'),
251 GeneralUtility::_GP('search_levels'),
252 GeneralUtility::_GP('showLimit')
253 );
254
255 $dbList->setDispFields();
256 $dbList->generateList();
257
258 $out .= $dbList->getSearchBox();
259
260 // Add the HTML for the record list to output variable:
261 $out .= $dbList->HTMLcode;
262
263 // Add support for fieldselectbox in singleTableMode
264 if ($dbList->table) {
265 $this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Recordlist/FieldSelectBox');
266 $out .= $dbList->fieldSelectBox($dbList->table);
267 }
268
269 return $out;
270 }
271
272 /**
273 * @return string[] Array of body-tag attributes
274 */
275 protected function getBodyTagAttributes()
276 {
277 return [
278 'data-mode' => 'db'
279 ];
280 }
281
282 /**
283 * @param array $values Array of values to include into the parameters
284 * @return string[] Array of parameters which have to be added to URLs
285 */
286 public function getUrlParameters(array $values)
287 {
288 $pid = $values['pid'] ?? $this->expandPage;
289 return [
290 'mode' => 'db',
291 'expandPage' => $pid,
292 'bparams' => $this->bparams
293 ];
294 }
295
296 /**
297 * @param array $values Values to be checked
298 * @return bool Returns TRUE if the given values match the currently selected item
299 */
300 public function isCurrentlySelectedItem(array $values)
301 {
302 return false;
303 }
304
305 /**
306 * Returns the URL of the current script
307 *
308 * @return string
309 */
310 public function getScriptUrl()
311 {
312 return $this->thisScript;
313 }
314 }