6f6b5d39edd0c0f8740fc0d8db420197c496882b
[Packages/TYPO3.CMS.git] / typo3 / sysext / recordlist / Classes / LinkHandler / PageLinkHandler.php
1 <?php
2 namespace TYPO3\CMS\Recordlist\LinkHandler;
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\ServerRequestInterface;
18 use TYPO3\CMS\Backend\Tree\View\ElementBrowserPageTreeView;
19 use TYPO3\CMS\Backend\Utility\BackendUtility;
20 use TYPO3\CMS\Core\Database\DatabaseConnection;
21 use TYPO3\CMS\Core\Imaging\Icon;
22 use TYPO3\CMS\Core\Page\PageRenderer;
23 use TYPO3\CMS\Core\Utility\GeneralUtility;
24 use TYPO3\CMS\Core\Utility\MathUtility;
25 use TYPO3\CMS\Recordlist\Tree\View\LinkParameterProviderInterface;
26
27 /**
28 * Link handler for page (and content) links
29 */
30 class PageLinkHandler extends AbstractLinkHandler implements LinkHandlerInterface, LinkParameterProviderInterface
31 {
32 /**
33 * @var int
34 */
35 protected $expandPage = 0;
36
37 /**
38 * Parts of the current link
39 *
40 * @var array
41 */
42 protected $linkParts = [];
43
44 /**
45 * Checks if this is the handler for the given link
46 *
47 * The handler may store this information locally for later usage.
48 *
49 * @param array $linkParts Link parts as returned from TypoLinkCodecService
50 *
51 * @return bool
52 */
53 public function canHandleLink(array $linkParts)
54 {
55 if (!$linkParts['url']) {
56 return false;
57 }
58
59 $id = $linkParts['url'];
60 $parts = explode('#', $id);
61 if (count($parts) > 1) {
62 $id = $parts[0];
63 $anchor = $parts[1];
64 } else {
65 $anchor = '';
66 }
67 // Checking if the id-parameter is an alias.
68 if (!MathUtility::canBeInterpretedAsInteger($id)) {
69 $records = BackendUtility::getRecordsByField('pages', 'alias', $id);
70 if (empty($records)) {
71 return false;
72 }
73 $id = (int)$records[0]['uid'];
74 }
75 $pageRow = BackendUtility::getRecordWSOL('pages', $id);
76 if (!$pageRow) {
77 return false;
78 }
79
80 $this->linkParts = $linkParts;
81 $this->linkParts['pageid'] = $id;
82 $this->linkParts['anchor'] = $anchor;
83
84 return true;
85 }
86
87 /**
88 * Format the current link for HTML output
89 *
90 * @return string
91 */
92 public function formatCurrentUrl()
93 {
94 $lang = $this->getLanguageService();
95 $titleLen = (int)$this->getBackendUser()->uc['titleLen'];
96
97 $id = $this->linkParts['pageid'];
98 $pageRow = BackendUtility::getRecordWSOL('pages', $id);
99
100 return $lang->getLL('page', true)
101 . ' \'' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($pageRow['title'], $titleLen)) . '\''
102 . ' (ID:' . $id . ($this->linkParts['anchor'] ? ', #' . $this->linkParts['anchor'] : '') . ')';
103 }
104
105 /**
106 * Render the link handler
107 *
108 * @param ServerRequestInterface $request
109 *
110 * @return string
111 */
112 public function render(ServerRequestInterface $request)
113 {
114 GeneralUtility::makeInstance(PageRenderer::class)->loadRequireJsModule('TYPO3/CMS/Recordlist/PageLinkHandler');
115
116 $this->expandPage = isset($request->getQueryParams()['expandPage']) ? (int)$request->getQueryParams()['expandPage'] : 0;
117 $this->setTemporaryDbMounts();
118
119 $backendUser = $this->getBackendUser();
120
121 /** @var ElementBrowserPageTreeView $pageTree */
122 $pageTree = GeneralUtility::makeInstance(ElementBrowserPageTreeView::class);
123 $pageTree->setLinkParameterProvider($this);
124 $pageTree->ext_showPageId = (bool)$backendUser->getTSConfigVal('options.pageTree.showPageIdWithTitle');
125 $pageTree->ext_showNavTitle = (bool)$backendUser->getTSConfigVal('options.pageTree.showNavTitle');
126 $pageTree->addField('nav_title');
127 $tree = $pageTree->getBrowsableTree();
128
129 return '
130
131 <!--
132 Wrapper table for page tree / record list:
133 -->
134 <table border="0" cellpadding="0" cellspacing="0" id="typo3-linkPages">
135 <tr>
136 <td class="c-wCell" valign="top"><h3>' . $this->getLanguageService()->getLL('pageTree') . ':</h3>'
137 . $this->getTemporaryTreeMountCancelNotice() . $tree . '</td>
138 <td class="c-wCell" valign="top">' . $this->expandPage($this->expandPage) . '</td>
139 </tr>
140 </table>';
141 }
142
143 /**
144 * This displays all content elements on a page and lets you create a link to the element.
145 *
146 * @param int $expPageId Page uid to expand
147 *
148 * @return string HTML output. Returns content only if the ->expandPage value is set (pointing to a page uid to show tt_content records from ...)
149 */
150 public function expandPage($expPageId)
151 {
152 // If there is an anchor value (content element reference) in the element reference, then force an ID to expand:
153 if (!$expPageId && isset($this->linkParts['anchor'])) {
154 // Set to the current link page id.
155 $expPageId = $this->linkParts['pageid'];
156 }
157 // Draw the record list IF there is a page id to expand:
158 if (!$expPageId || !MathUtility::canBeInterpretedAsInteger($expPageId) || !$this->getBackendUser()->isInWebMount($expPageId)) {
159 return '';
160 }
161
162 // Set header:
163 $out = '<h3>' . $this->getLanguageService()->getLL('contentElements') . ':</h3>';
164 // Create header for listing, showing the page title/icon:
165 $mainPageRec = BackendUtility::getRecordWSOL('pages', $expPageId);
166 $db = $this->getDatabaseConnection();
167 $out .= '
168 <ul class="list-tree list-tree-root list-tree-root-clean">
169 <li class="list-tree-control-open">
170 <span class="list-tree-group">
171 <span class="list-tree-icon">' . $this->iconFactory->getIconForRecord('pages', $mainPageRec, Icon::SIZE_SMALL)->render() . '</span>
172 <span class="list-tree-title">' . htmlspecialchars(BackendUtility::getRecordTitle('pages', $mainPageRec, true)) . '</span>
173 </span>
174 <ul>
175 ';
176
177 // Look up tt_content elements from the expanded page:
178 $res = $db->exec_SELECTquery(
179 '*',
180 'tt_content',
181 'pid=' . (int)$expPageId . BackendUtility::deleteClause('tt_content')
182 . BackendUtility::versioningPlaceholderClause('tt_content'),
183 '',
184 'colPos,sorting'
185 );
186 // Traverse list of records:
187 $c = 0;
188 while ($row = $db->sql_fetch_assoc($res)) {
189 $c++;
190 $icon = $this->iconFactory->getIconForRecord('tt_content', $row, Icon::SIZE_SMALL)->render();
191 $selected = '';
192 if (!empty($this->linkParts) && (int)$this->linkParts['anchor'] === (int)$row['uid']) {
193 $selected = ' class="active"';
194 }
195 // Putting list element HTML together:
196 // Output of BackendUtility::getRecordTitle() is already hsc'ed
197 $out .= '
198 <li' . $selected . '>
199 <span class="list-tree-group">
200 <span class="list-tree-icon">
201 ' . $icon . '
202 </span>
203 <span class="list-tree-title">
204 <a href="#" class="t3js-pageLink" data-id="' . (int)$expPageId . '" data-anchor="#' . (int)$row['uid'] . '">
205 ' . BackendUtility::getRecordTitle('tt_content', $row, true) . '
206 </a>
207 </span>
208 </span>
209 </li>
210 ';
211 }
212 $out .= '
213 </ul>
214 </li>
215 </ul>
216 ';
217
218 return $out;
219 }
220
221 /**
222 * Check if a temporary tree mount is set and return a cancel button
223 *
224 * @return string HTML code
225 */
226 protected function getTemporaryTreeMountCancelNotice()
227 {
228 if ((int)$this->getBackendUser()->getSessionData('pageTree_temporaryMountPoint') === 0) {
229 return '';
230 }
231 $link = '<p><a href="' . htmlspecialchars(GeneralUtility::linkThisScript(['setTempDBmount' => 0])) . '" class="btn btn-primary">'
232 . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:labels.temporaryDBmount', true) . '</a></p>';
233 return $link;
234 }
235
236 /**
237 * @return void
238 */
239 protected function setTemporaryDbMounts()
240 {
241 $backendUser = $this->getBackendUser();
242
243 // Clear temporary DB mounts
244 $tmpMount = GeneralUtility::_GET('setTempDBmount');
245 if (isset($tmpMount)) {
246 $backendUser->setAndSaveSessionData('pageTree_temporaryMountPoint', (int)$tmpMount);
247 }
248 // Set temporary DB mounts
249 $alternativeWebmountPoint = (int)$backendUser->getSessionData('pageTree_temporaryMountPoint');
250 if ($alternativeWebmountPoint) {
251 $alternativeWebmountPoint = GeneralUtility::intExplode(',', $alternativeWebmountPoint);
252 $backendUser->setWebmounts($alternativeWebmountPoint);
253 } else {
254 // Setting alternative browsing mounts (ONLY local to browse_links.php this script so they stay "read-only")
255 $alternativeWebmountPoints = trim($backendUser->getTSConfigVal('options.pageTree.altElementBrowserMountPoints'));
256 $appendAlternativeWebmountPoints = $backendUser->getTSConfigVal('options.pageTree.altElementBrowserMountPoints.append');
257 if ($alternativeWebmountPoints) {
258 $alternativeWebmountPoints = GeneralUtility::intExplode(',', $alternativeWebmountPoints);
259 $this->getBackendUser()->setWebmounts($alternativeWebmountPoints, $appendAlternativeWebmountPoints);
260 }
261 }
262 }
263
264 /**
265 * @return string[] Array of body-tag attributes
266 */
267 public function getBodyTagAttributes()
268 {
269 if (empty($this->linkParts)) {
270 return [];
271 }
272 return [
273 'data-current-link' => $this->linkParts['pageid'] . ($this->linkParts['anchor'] !== '' ? '#' . $this->linkParts['anchor'] : '')
274 ];
275 }
276
277 /**
278 * @param array $values Array of values to include into the parameters or which might influence the parameters
279 *
280 * @return string[] Array of parameters which have to be added to URLs
281 */
282 public function getUrlParameters(array $values)
283 {
284 $parameters = [
285 'expandPage' => isset($values['pid']) ? (int)$values['pid'] : $this->expandPage
286 ];
287 return array_merge($this->linkBrowser->getUrlParameters($values), $parameters);
288 }
289
290 /**
291 * @param array $values Values to be checked
292 *
293 * @return bool Returns TRUE if the given values match the currently selected item
294 */
295 public function isCurrentlySelectedItem(array $values)
296 {
297 return !empty($this->linkParts) && (int)$this->linkParts['pageid'] === (int)$values['pid'];
298 }
299
300 /**
301 * Returns the URL of the current script
302 *
303 * @return string
304 */
305 public function getScriptUrl()
306 {
307 return $this->linkBrowser->getScriptUrl();
308 }
309
310 /**
311 * @param string[] $fieldDefinitions Array of link attribute field definitions
312 * @return string[]
313 */
314 public function modifyLinkAttributes(array $fieldDefinitions)
315 {
316 $configuration = $this->linkBrowser->getConfiguration();
317 if (!empty($configuration['pageIdSelector.']['enabled'])) {
318 array_push($this->linkAttributes, 'pageIdSelector');
319 $fieldDefinitions['pageIdSelector'] = '
320 <tr>
321 <td>
322 <label>
323 ' . $this->getLanguageService()->getLL('page_id', true) . ':
324 </label>
325 </td>
326 <td colspan="3">
327 <input type="text" size="6" name="luid" id="luid" /> <input class="btn btn-default t3js-pageLink" type="submit" value="'
328 . $this->getLanguageService()->getLL('setLink', true) . '" />
329 </td>
330 </tr>';
331 }
332 return $fieldDefinitions;
333 }
334
335 /**
336 * @return DatabaseConnection
337 */
338 protected function getDatabaseConnection()
339 {
340 return $GLOBALS['TYPO3_DB'];
341 }
342 }