4c6358f6b3376c6a10237b7dd78ac336b37a41be
[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\ConnectionPool;
21 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
22 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
23 use TYPO3\CMS\Core\Imaging\Icon;
24 use TYPO3\CMS\Core\LinkHandling\LinkService;
25 use TYPO3\CMS\Core\Page\PageRenderer;
26 use TYPO3\CMS\Core\Utility\GeneralUtility;
27 use TYPO3\CMS\Core\Utility\MathUtility;
28 use TYPO3\CMS\Recordlist\Tree\View\LinkParameterProviderInterface;
29
30 /**
31 * Link handler for page (and content) links
32 */
33 class PageLinkHandler extends AbstractLinkHandler implements LinkHandlerInterface, LinkParameterProviderInterface
34 {
35 /**
36 * @var int
37 */
38 protected $expandPage = 0;
39
40 /**
41 * Parts of the current link
42 *
43 * @var array
44 */
45 protected $linkParts = [];
46
47 /**
48 * Checks if this is the handler for the given link
49 *
50 * The handler may store this information locally for later usage.
51 *
52 * @param array $linkParts Link parts as returned from TypoLinkCodecService
53 *
54 * @return bool
55 */
56 public function canHandleLink(array $linkParts)
57 {
58 if (!$linkParts['url']) {
59 return false;
60 }
61
62 $data = $linkParts['url'];
63 // Checking if the id-parameter is an alias.
64 if (isset($data['pagealias'])) {
65 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
66 ->getQueryBuilderForTable('pages');
67 $queryBuilder->getRestrictions()
68 ->removeAll()
69 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
70 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
71
72 $pageUid = $queryBuilder->select('uid')
73 ->from('pages')
74 ->where(
75 $queryBuilder->expr()->eq(
76 'alias',
77 $queryBuilder->createNamedParameter($data['pagealias'], \PDO::PARAM_STR)
78 )
79 )
80 ->setMaxResults(1)
81 ->execute()
82 ->fetchColumn(0);
83
84 if ($pageUid === false) {
85 return false;
86 }
87 $data['pageuid'] = (int)$pageUid;
88 }
89 // Check if the page still exists
90 if ((int)$data['pageuid'] > 0) {
91 $pageRow = BackendUtility::getRecordWSOL('pages', $data['pageuid']);
92 if (!$pageRow) {
93 return false;
94 }
95 } elseif ($data['pageuid'] !== 'current') {
96 return false;
97 }
98
99 $this->linkParts = $linkParts;
100 return true;
101 }
102
103 /**
104 * Format the current link for HTML output
105 *
106 * @return string
107 */
108 public function formatCurrentUrl()
109 {
110 $lang = $this->getLanguageService();
111 $titleLen = (int)$this->getBackendUser()->uc['titleLen'];
112
113 $id = $this->linkParts['url']['pageuid'];
114 $pageRow = BackendUtility::getRecordWSOL('pages', $id);
115
116 return htmlspecialchars($lang->getLL('page'))
117 . ' \'' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($pageRow['title'], $titleLen)) . '\''
118 . ' (ID: ' . $id . ($this->linkParts['url']['fragment'] ? ', #' . $this->linkParts['url']['fragment'] : '') . ')';
119 }
120
121 /**
122 * Render the link handler
123 *
124 * @param ServerRequestInterface $request
125 *
126 * @return string
127 */
128 public function render(ServerRequestInterface $request)
129 {
130 GeneralUtility::makeInstance(PageRenderer::class)->loadRequireJsModule('TYPO3/CMS/Recordlist/PageLinkHandler');
131
132 $this->expandPage = isset($request->getQueryParams()['expandPage']) ? (int)$request->getQueryParams()['expandPage'] : 0;
133 $this->setTemporaryDbMounts();
134
135 $backendUser = $this->getBackendUser();
136
137 /** @var ElementBrowserPageTreeView $pageTree */
138 $pageTree = GeneralUtility::makeInstance(ElementBrowserPageTreeView::class);
139 $pageTree->setLinkParameterProvider($this);
140 $pageTree->ext_showNavTitle = (bool)$backendUser->getTSConfigVal('options.pageTree.showNavTitle');
141 $pageTree->ext_showPageId = (bool)$backendUser->getTSConfigVal('options.pageTree.showPageIdWithTitle');
142 $pageTree->ext_showPathAboveMounts = (bool)$backendUser->getTSConfigVal('options.pageTree.showPathAboveMounts');
143 $pageTree->addField('nav_title');
144
145 $this->view->assign('temporaryTreeMountCancelLink', $this->getTemporaryTreeMountCancelNotice());
146 $this->view->assign('tree', $pageTree->getBrowsableTree());
147 $this->getRecordsOnExpandedPage($this->expandPage);
148 return $this->view->render('Page');
149 }
150
151 /**
152 * This adds all content elements on a page to the view and lets you create a link to the element.
153 *
154 * @param int $pageId Page uid to expand
155 */
156 protected function getRecordsOnExpandedPage($pageId)
157 {
158 // If there is an anchor value (content element reference) in the element reference, then force an ID to expand:
159 if (!$pageId && isset($this->linkParts['url']['fragment'])) {
160 // Set to the current link page id.
161 $pageId = $this->linkParts['url']['pageuid'];
162 }
163 // Draw the record list IF there is a page id to expand:
164 if ($pageId && MathUtility::canBeInterpretedAsInteger($pageId) && $this->getBackendUser()->isInWebMount($pageId)) {
165 $pageId = (int)$pageId;
166
167 $activePageRecord = BackendUtility::getRecordWSOL('pages', $pageId);
168 $this->view->assign('expandActivePage', true);
169
170 // Create header for listing, showing the page title/icon
171 $this->view->assign('activePage', $activePageRecord);
172 $this->view->assign('activePageTitle', BackendUtility::getRecordTitle('pages', $activePageRecord, true));
173 $this->view->assign('activePageIcon', $this->iconFactory->getIconForRecord('pages', $activePageRecord, Icon::SIZE_SMALL)->render());
174
175 // Look up tt_content elements from the expanded page
176 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
177 ->getQueryBuilderForTable('tt_content');
178
179 $queryBuilder->getRestrictions()
180 ->removeAll()
181 ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
182 ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
183
184 $contentElements = $queryBuilder
185 ->select('*')
186 ->from('tt_content')
187 ->where(
188 $queryBuilder->expr()->eq(
189 'pid',
190 $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
191 )
192 )
193 ->orderBy('colPos')
194 ->addOrderBy('sorting')
195 ->execute()
196 ->fetchAll();
197
198 // Enrich list of records
199 foreach ($contentElements as &$contentElement) {
200 $contentElement['url'] = GeneralUtility::makeInstance(LinkService::class)->asString(['type' => LinkService::TYPE_PAGE, 'pageuid' => (int)$pageId, 'fragment' => $contentElement['uid']]);
201 $contentElement['isSelected'] = !empty($this->linkParts) && (int)$this->linkParts['url']['fragment'] === (int)$contentElement['uid'];
202 $contentElement['icon'] = $this->iconFactory->getIconForRecord('tt_content', $contentElement, Icon::SIZE_SMALL)->render();
203 $contentElement['title'] = BackendUtility::getRecordTitle('tt_content', $contentElement, true);
204 }
205 $this->view->assign('contentElements', $contentElements);
206 }
207 }
208
209 /**
210 * Check if a temporary tree mount is set and return a cancel button link
211 *
212 * @return string the link to cancel the temporary tree mount
213 */
214 protected function getTemporaryTreeMountCancelNotice()
215 {
216 if ((int)$this->getBackendUser()->getSessionData('pageTree_temporaryMountPoint') > 0) {
217 return GeneralUtility::linkThisScript(['setTempDBmount' => 0]);
218 } else {
219 return '';
220 }
221 }
222
223 /**
224 * Sets a DB mount and stores it in the currently defined backend user in her/his uc
225 */
226 protected function setTemporaryDbMounts()
227 {
228 $backendUser = $this->getBackendUser();
229
230 // Clear temporary DB mounts
231 $tmpMount = GeneralUtility::_GET('setTempDBmount');
232 if (isset($tmpMount)) {
233 $backendUser->setAndSaveSessionData('pageTree_temporaryMountPoint', (int)$tmpMount);
234 }
235 // Set temporary DB mounts
236 $alternativeWebmountPoint = (int)$backendUser->getSessionData('pageTree_temporaryMountPoint');
237 if ($alternativeWebmountPoint) {
238 $alternativeWebmountPoint = GeneralUtility::intExplode(',', $alternativeWebmountPoint);
239 $backendUser->setWebmounts($alternativeWebmountPoint);
240 } else {
241 // Setting alternative browsing mounts (ONLY local to browse_links.php this script so they stay "read-only")
242 $alternativeWebmountPoints = trim($backendUser->getTSConfigVal('options.pageTree.altElementBrowserMountPoints'));
243 $appendAlternativeWebmountPoints = $backendUser->getTSConfigVal('options.pageTree.altElementBrowserMountPoints.append');
244 if ($alternativeWebmountPoints) {
245 $alternativeWebmountPoints = GeneralUtility::intExplode(',', $alternativeWebmountPoints);
246 $this->getBackendUser()->setWebmounts($alternativeWebmountPoints, $appendAlternativeWebmountPoints);
247 }
248 }
249 }
250
251 /**
252 * @return string[] Array of body-tag attributes
253 */
254 public function getBodyTagAttributes()
255 {
256 if (count($this->linkParts) === 0 || empty($this->linkParts['url']['pageuid'])) {
257 return [];
258 }
259 return [
260 'data-current-link' => GeneralUtility::makeInstance(LinkService::class)->asString([
261 'type' => LinkService::TYPE_PAGE,
262 'pageuid' => (int)$this->linkParts['url']['pageuid'],
263 'fragment' => $this->linkParts['url']['fragment']
264 ])
265 ];
266 }
267
268 /**
269 * @param array $values Array of values to include into the parameters or which might influence the parameters
270 *
271 * @return string[] Array of parameters which have to be added to URLs
272 */
273 public function getUrlParameters(array $values)
274 {
275 $parameters = [
276 'expandPage' => isset($values['pid']) ? (int)$values['pid'] : $this->expandPage
277 ];
278 return array_merge($this->linkBrowser->getUrlParameters($values), $parameters);
279 }
280
281 /**
282 * @param array $values Values to be checked
283 *
284 * @return bool Returns TRUE if the given values match the currently selected item
285 */
286 public function isCurrentlySelectedItem(array $values)
287 {
288 return !empty($this->linkParts) && (int)$this->linkParts['url']['pageuid'] === (int)$values['pid'];
289 }
290
291 /**
292 * Returns the URL of the current script
293 *
294 * @return string
295 */
296 public function getScriptUrl()
297 {
298 return $this->linkBrowser->getScriptUrl();
299 }
300
301 /**
302 * @param string[] $fieldDefinitions Array of link attribute field definitions
303 * @return string[]
304 */
305 public function modifyLinkAttributes(array $fieldDefinitions)
306 {
307 $configuration = $this->linkBrowser->getConfiguration();
308 if (!empty($configuration['pageIdSelector.']['enabled'])) {
309 $this->linkAttributes[] = 'pageIdSelector';
310 $fieldDefinitions['pageIdSelector'] = '
311 <tr>
312 <td>
313 <label>
314 ' . htmlspecialchars($this->getLanguageService()->getLL('page_id')) . ':
315 </label>
316 </td>
317 <td colspan="3">
318 <input type="text" size="6" name="luid" id="luid" /> <input class="btn btn-default t3js-pageLink" type="submit" value="'
319 . htmlspecialchars($this->getLanguageService()->getLL('setLink')) . '" />
320 </td>
321 </tr>';
322 }
323 return $fieldDefinitions;
324 }
325 }