[BUGFIX] Linkhandler - access to data outside editors pagetree
[Packages/TYPO3.CMS.git] / typo3 / sysext / recordlist / Classes / LinkHandler / RecordLinkHandler.php
1 <?php
2 declare(strict_types=1);
3 namespace TYPO3\CMS\Recordlist\LinkHandler;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Utility\BackendUtility;
20 use TYPO3\CMS\Core\LinkHandling\LinkService;
21 use TYPO3\CMS\Core\Page\PageRenderer;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Fluid\View\StandaloneView;
24 use TYPO3\CMS\Recordlist\Browser\RecordBrowser;
25 use TYPO3\CMS\Recordlist\Controller\AbstractLinkBrowserController;
26 use TYPO3\CMS\Recordlist\Tree\View\LinkParameterProviderInterface;
27 use TYPO3\CMS\Recordlist\Tree\View\RecordBrowserPageTreeView;
28
29 /**
30 * Link handler for arbitrary database records
31 */
32 class RecordLinkHandler extends AbstractLinkHandler implements LinkHandlerInterface, LinkParameterProviderInterface
33 {
34 /**
35 * Configuration key in TSconfig TCEMAIN.linkHandler.record
36 *
37 * @var string
38 */
39 protected $identifier;
40
41 /**
42 * Specific TSconfig for the current instance (corresponds to TCEMAIN.linkHandler.record.identifier.configuration)
43 *
44 * @var array
45 */
46 protected $configuration = [];
47
48 /**
49 * Parts of the current link
50 *
51 * @var array
52 */
53 protected $linkParts = [];
54
55 /**
56 * @var int
57 */
58 protected $expandPage = 0;
59
60 /**
61 * Initializes the handler.
62 *
63 * @param AbstractLinkBrowserController $linkBrowser
64 * @param string $identifier
65 * @param array $configuration Page TSconfig
66 */
67 public function initialize(AbstractLinkBrowserController $linkBrowser, $identifier, array $configuration)
68 {
69 parent::initialize($linkBrowser, $identifier, $configuration);
70 $this->identifier = $identifier;
71 $this->configuration = $configuration;
72 }
73
74 /**
75 * Checks if this is the right handler for the given link.
76 *
77 * Also stores information locally about currently linked record.
78 *
79 * @param array $linkParts Link parts as returned from TypoLinkCodecService
80 * @return bool
81 */
82 public function canHandleLink(array $linkParts): bool
83 {
84 if (!$linkParts['url'] || !isset($linkParts['url']['identifier']) || $linkParts['url']['identifier'] !== $this->identifier) {
85 return false;
86 }
87
88 $data = $linkParts['url'];
89
90 // Get the related record
91 $table = $this->configuration['table'];
92 $record = BackendUtility::getRecord($table, $data['uid']);
93 if ($record === null) {
94 $linkParts['title'] = $this->getLanguageService()->getLL('recordNotFound');
95 } else {
96 $linkParts['tableName'] = $this->getLanguageService()->sL($GLOBALS['TCA'][$table]['ctrl']['title']);
97 $linkParts['pid'] = (int)$record['pid'];
98 $linkParts['title'] = $linkParts['title'] ?: BackendUtility::getRecordTitle($table, $record);
99 }
100 $linkParts['url']['type'] = $linkParts['type'];
101 $this->linkParts = $linkParts;
102
103 return true;
104 }
105
106 /**
107 * Formats information for the current record for HTML output.
108 *
109 * @return string
110 */
111 public function formatCurrentUrl(): string
112 {
113 return sprintf(
114 '%s: %s [uid: %d]',
115 $this->linkParts['tableName'],
116 $this->linkParts['title'],
117 $this->linkParts['url']['uid']
118 );
119 }
120
121 /**
122 * Renders the link handler.
123 *
124 * @param ServerRequestInterface $request
125 * @return string
126 */
127 public function render(ServerRequestInterface $request): string
128 {
129 // Declare JS module
130 GeneralUtility::makeInstance(PageRenderer::class)->loadRequireJsModule('TYPO3/CMS/Recordlist/RecordLinkHandler');
131
132 // Define the current page
133 if (isset($request->getQueryParams()['expandPage'])) {
134 $this->expandPage = (int)$request->getQueryParams()['expandPage'];
135 } elseif (isset($this->configuration['storagePid'])) {
136 $this->expandPage = (int)$this->configuration['storagePid'];
137 } elseif (isset($this->linkParts['pid'])) {
138 $this->expandPage = (int)$this->linkParts['pid'];
139 }
140 $this->setTemporaryDbMounts();
141
142 $databaseBrowser = GeneralUtility::makeInstance(RecordBrowser::class);
143
144 $recordList = $databaseBrowser->displayRecordsForPage(
145 $this->expandPage,
146 $this->configuration['table'],
147 $this->getUrlParameters([])
148 );
149
150 $path = GeneralUtility::getFileAbsFileName('EXT:recordlist/Resources/Private/Templates/LinkBrowser/Record.html');
151 $view = GeneralUtility::makeInstance(StandaloneView::class);
152 $view->setTemplatePathAndFilename($path);
153 $view->assignMultiple([
154 'tree' => $this->configuration['hidePageTree'] ? '' : $this->renderPageTree(),
155 'recordList' => $recordList,
156 ]);
157
158 return $view->render();
159 }
160
161 /**
162 * Renders the page tree.
163 *
164 * @return string
165 */
166 protected function renderPageTree(): string
167 {
168 $backendUser = $this->getBackendUser();
169
170 /** @var RecordBrowserPageTreeView $pageTree */
171 $pageTree = GeneralUtility::makeInstance(RecordBrowserPageTreeView::class);
172 $pageTree->setLinkParameterProvider($this);
173 $pageTree->ext_showPageId = (bool)$backendUser->getTSConfigVal('options.pageTree.showPageIdWithTitle');
174 $pageTree->ext_showNavTitle = (bool)$backendUser->getTSConfigVal('options.pageTree.showNavTitle');
175 $pageTree->ext_showPathAboveMounts = (bool)$backendUser->getTSConfigVal('options.pageTree.showPathAboveMounts');
176 $pageTree->addField('nav_title');
177
178 // Load the mount points, if any
179 // NOTE: mount points actually override the page tree
180 if (!empty($this->configuration['pageTreeMountPoints'])) {
181 $pageTree->MOUNTS = GeneralUtility::intExplode(',', $this->configuration['pageTreeMountPoints'], true);
182 }
183
184 return $pageTree->getBrowsableTree();
185 }
186
187 /**
188 * Returns attributes for the body tag.
189 *
190 * @return string[] Array of body-tag attributes
191 */
192 public function getBodyTagAttributes(): array
193 {
194 $attributes = [
195 'data-identifier' => 't3://record?identifier=' . $this->identifier . '&uid=',
196 ];
197 if (!empty($this->linkParts)) {
198 $attributes['data-current-link'] = GeneralUtility::makeInstance(LinkService::class)->asString($this->linkParts['url']);
199 }
200
201 return $attributes;
202 }
203
204 /**
205 * Returns all parameters needed to build a URL with all the necessary information.
206 *
207 * @param array $values Array of values to include into the parameters or which might influence the parameters
208 * @return string[] Array of parameters which have to be added to URLs
209 */
210 public function getUrlParameters(array $values): array
211 {
212 $pid = isset($values['pid']) ? (int)$values['pid'] : $this->expandPage;
213 $parameters = [
214 'expandPage' => $pid,
215 ];
216
217 return array_merge(
218 $this->linkBrowser->getUrlParameters($values),
219 ['P' => $this->linkBrowser->getParameters()],
220 $parameters
221 );
222 }
223
224 /**
225 * Checks if the submitted page matches the current page.
226 *
227 * @param array $values Values to be checked
228 * @return bool Returns TRUE if the given values match the currently selected item
229 */
230 public function isCurrentlySelectedItem(array $values): bool
231 {
232 return !empty($this->linkParts) && (int)$this->linkParts['pid'] === (int)$values['pid'];
233 }
234
235 /**
236 * Returns the URL of the current script
237 *
238 * @return string
239 */
240 public function getScriptUrl(): string
241 {
242 return $this->linkBrowser->getScriptUrl();
243 }
244 }