[BUGFIX] Add label to page ID field in PageLinkHandler
[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 }
219 return '';
220 }
221
222 /**
223 * Sets a DB mount and stores it in the currently defined backend user in her/his uc
224 */
225 protected function setTemporaryDbMounts()
226 {
227 $backendUser = $this->getBackendUser();
228
229 // Clear temporary DB mounts
230 $tmpMount = GeneralUtility::_GET('setTempDBmount');
231 if (isset($tmpMount)) {
232 $backendUser->setAndSaveSessionData('pageTree_temporaryMountPoint', (int)$tmpMount);
233 }
234 // Set temporary DB mounts
235 $alternativeWebmountPoint = (int)$backendUser->getSessionData('pageTree_temporaryMountPoint');
236 if ($alternativeWebmountPoint) {
237 $alternativeWebmountPoint = GeneralUtility::intExplode(',', $alternativeWebmountPoint);
238 $backendUser->setWebmounts($alternativeWebmountPoint);
239 } else {
240 // Setting alternative browsing mounts (ONLY local to browse_links.php this script so they stay "read-only")
241 $alternativeWebmountPoints = trim($backendUser->getTSConfigVal('options.pageTree.altElementBrowserMountPoints'));
242 $appendAlternativeWebmountPoints = $backendUser->getTSConfigVal('options.pageTree.altElementBrowserMountPoints.append');
243 if ($alternativeWebmountPoints) {
244 $alternativeWebmountPoints = GeneralUtility::intExplode(',', $alternativeWebmountPoints);
245 $this->getBackendUser()->setWebmounts($alternativeWebmountPoints, $appendAlternativeWebmountPoints);
246 }
247 }
248 }
249
250 /**
251 * @return string[] Array of body-tag attributes
252 */
253 public function getBodyTagAttributes()
254 {
255 if (count($this->linkParts) === 0 || empty($this->linkParts['url']['pageuid'])) {
256 return [];
257 }
258 return [
259 'data-current-link' => GeneralUtility::makeInstance(LinkService::class)->asString([
260 'type' => LinkService::TYPE_PAGE,
261 'pageuid' => (int)$this->linkParts['url']['pageuid'],
262 'fragment' => $this->linkParts['url']['fragment']
263 ])
264 ];
265 }
266
267 /**
268 * @param array $values Array of values to include into the parameters or which might influence the parameters
269 *
270 * @return string[] Array of parameters which have to be added to URLs
271 */
272 public function getUrlParameters(array $values)
273 {
274 $parameters = [
275 'expandPage' => isset($values['pid']) ? (int)$values['pid'] : $this->expandPage
276 ];
277 return array_merge($this->linkBrowser->getUrlParameters($values), $parameters);
278 }
279
280 /**
281 * @param array $values Values to be checked
282 *
283 * @return bool Returns TRUE if the given values match the currently selected item
284 */
285 public function isCurrentlySelectedItem(array $values)
286 {
287 return !empty($this->linkParts) && (int)$this->linkParts['url']['pageuid'] === (int)$values['pid'];
288 }
289
290 /**
291 * Returns the URL of the current script
292 *
293 * @return string
294 */
295 public function getScriptUrl()
296 {
297 return $this->linkBrowser->getScriptUrl();
298 }
299
300 /**
301 * @param string[] $fieldDefinitions Array of link attribute field definitions
302 * @return string[]
303 */
304 public function modifyLinkAttributes(array $fieldDefinitions)
305 {
306 $configuration = $this->linkBrowser->getConfiguration();
307 if (!empty($configuration['pageIdSelector.']['enabled'])) {
308 $this->linkAttributes[] = 'pageIdSelector';
309 $fieldDefinitions['pageIdSelector'] = '
310 <form class="form-horizontal"><div class="form-group form-group-sm">
311 <label class="col-xs-4 control-label">
312 ' . htmlspecialchars($this->getLanguageService()->getLL('page_id')) . '
313 </label>
314 <div class="col-xs-2">
315 <input type="number" size="6" name="luid" id="luid" class="form-control" />
316 </div>
317 <div class="col-xs-6">
318 <input class="btn btn-default t3js-pageLink" type="submit" value="' . htmlspecialchars($this->getLanguageService()->getLL('setLink')) . '" />
319 </div>
320 </div></form>';
321 }
322 return $fieldDefinitions;
323 }
324 }