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