‪TYPO3CMS  11.5
PreviewUriBuilder.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
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 
19 
20 use Psr\EventDispatcher\EventDispatcherInterface;
21 use Psr\Http\Message\UriInterface;
23 use ‪TYPO3\CMS\Backend\Routing\PreviewUriBuilder as BackendPreviewUriBuilder;
25 use TYPO3\CMS\Backend\Utility\BackendUtility;
39 
46 {
50  protected ‪$pageCache = [];
51 
55  protected ‪$workspaceService;
56 
60  protected ‪$eventDispatcher;
61 
65  protected ‪$previewLinkLifetime;
66 
67  public function ‪__construct(EventDispatcherInterface ‪$eventDispatcher, ‪WorkspaceService ‪$workspaceService)
68  {
69  $this->eventDispatcher = ‪$eventDispatcher;
70  $this->workspaceService = ‪$workspaceService;
71  $this->previewLinkLifetime = $this->workspaceService->‪getPreviewLinkLifetime();
72  }
73 
81  public function ‪buildUriForPage(int $uid, int $languageId = 0): string
82  {
83  $previewKeyword = $this->‪compilePreviewKeyword(
84  $this->previewLinkLifetime * 3600,
85  $this->workspaceService->getCurrentWorkspace()
86  );
87 
88  $siteFinder = GeneralUtility::makeInstance(SiteFinder::class);
89  try {
90  $site = $siteFinder->getSiteByPageId($uid);
91  try {
92  $language = $site->getLanguageById($languageId);
93  } catch (\InvalidArgumentException $e) {
94  $language = $site->getDefaultLanguage();
95  }
96  $uri = $site->getRouter()->generateUri($uid, ['ADMCMD_prev' => $previewKeyword, '_language' => $language], '');
97  return (string)$uri;
98  } catch (SiteNotFoundException | InvalidRouteArgumentsException $e) {
99  throw new UnableToLinkToPageException(sprintf('The link to the page with ID "%d" could not be generated: %s', $uid, $e->getMessage()), 1559794916, $e);
100  }
101  }
102 
109  public function ‪buildUrisForAllLanguagesOfPage(int $pageId): array
110  {
111  $previewLanguages = $this->‪getAvailableLanguages($pageId);
112  $previewLinks = [];
113 
114  foreach ($previewLanguages as $languageUid => $language) {
115  $previewLinks[$language] = $this->‪buildUriForPage($pageId, $languageUid);
116  }
117 
118  return $previewLinks;
119  }
120 
128  public function ‪buildUriForWorkspaceSplitPreview(int $uid): UriInterface
129  {
130  // In case a $pageUid is submitted we need to make sure it points to a live-page
131  if ($uid > 0) {
132  $uid = $this->‪getLivePageUid($uid);
133  }
134  $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
135  return $uriBuilder->buildUriFromRoute(
136  'workspace_previewcontrols',
137  ['id' => $uid],
139  );
140  }
141 
151  public function ‪buildUriForElement(string $table, int $uid, ?array $liveRecord = null, ?array $versionRecord = null): string
152  {
153  $previewUri = $this->‪createPreviewUriForElement($table, $uid, $liveRecord, $versionRecord);
154  $event = new RetrievedPreviewUrlEvent($table, $uid, $previewUri, [
155  'liveRecord' => $liveRecord,
156  'versionRecord' => $versionRecord,
157  ]);
159  $event = $this->eventDispatcher->dispatch($event);
160  $previewUri = (string)($event->getPreviewUri() ?? '');
161  return $previewUri;
162  }
163 
164  protected function ‪createPreviewUriForElement(string $table, int $uid, ?array $liveRecord = null, ?array $versionRecord = null): ?UriInterface
165  {
166  if ($table === 'pages') {
167  return BackendPreviewUriBuilder::create((int)BackendUtility::getLiveVersionIdOfRecord('pages', $uid))
168  ->buildUri();
169  }
170 
171  if ($liveRecord === null) {
172  $liveRecord = BackendUtility::getLiveVersionOfRecord($table, $uid);
173  }
174  if ($versionRecord === null) {
175  $versionRecord = BackendUtility::getRecord($table, $uid);
176  }
177 
178  // Directly use pid value and consider move placeholders
179  $previewPageId = (int)(empty($versionRecord['pid']) ? $liveRecord['pid'] : $versionRecord['pid']);
180  $additionalParameters = '&previewWS=' . $versionRecord['t3ver_wsid'];
181  // Add language parameter if record is a localization
182  if (BackendUtility::isTableLocalizable($table)) {
183  $languageField = ‪$GLOBALS['TCA'][$table]['ctrl']['languageField'];
184  if ($versionRecord[$languageField] > 0) {
185  $additionalParameters .= '&L=' . $versionRecord[$languageField];
186  }
187  }
188 
189  $pageTsConfig = BackendUtility::getPagesTSconfig($previewPageId);
190  // Directly use determined direct page id
191  if ($table === 'tt_content') {
192  return BackendPreviewUriBuilder::create($previewPageId)
193  ->withAdditionalQueryParameters($additionalParameters)
194  ->buildUri();
195  }
196  if (!empty($pageTsConfig['options.']['workspaces.']['previewPageId.'][$table]) || !empty($pageTsConfig['options.']['workspaces.']['previewPageId'])) {
197  // Analyze Page TSconfig options.workspaces.previewPageId
198  if (!empty($pageTsConfig['options.']['workspaces.']['previewPageId.'][$table])) {
199  $previewConfiguration = $pageTsConfig['options.']['workspaces.']['previewPageId.'][$table];
200  } else {
201  $previewConfiguration = $pageTsConfig['options.']['workspaces.']['previewPageId'];
202  }
203  // Extract possible settings (e.g. "field:pid")
204  $previewValueParts = explode(':', $previewConfiguration, 2);
205  if (count($previewValueParts) === 2 && $previewValueParts[0] === 'field') {
206  $previewPageId = (int)($liveRecord[$previewValueParts[1]] ?? 0);
207  } else {
208  $previewPageId = (int)$previewConfiguration;
209  }
210  return BackendPreviewUriBuilder::create($previewPageId)
211  ->withAdditionalQueryParameters($additionalParameters)
212  ->buildUri();
213  }
214  return null;
215  }
216 
224  protected function ‪compilePreviewKeyword(int $ttl = 172800, ?int $workspaceId = null): string
225  {
226  $keyword = md5(‪StringUtility::getUniqueId());
227  GeneralUtility::makeInstance(ConnectionPool::class)
228  ->getConnectionForTable('sys_preview')
229  ->insert(
230  'sys_preview',
231  [
232  'keyword' => $keyword,
233  'tstamp' => ‪$GLOBALS['EXEC_TIME'],
234  'endtime' => ‪$GLOBALS['EXEC_TIME'] + $ttl,
235  'config' => json_encode([
236  'fullWorkspace' => $workspaceId,
237  ]),
238  ]
239  );
240 
241  return $keyword;
242  }
243 
252  protected function ‪getLivePageUid(int $uid): int
253  {
254  if (!isset($this->pageCache[$uid])) {
255  $pageRecord = BackendUtility::getRecord('pages', $uid);
256  if (is_array($pageRecord)) {
257  $this->pageCache[$uid] = $pageRecord['t3ver_oid'] ? (int)$pageRecord['t3ver_oid'] : $uid;
258  } else {
259  throw new \InvalidArgumentException('uid is supposed to point to an existing page - given value was: ' . $uid, 1290628113);
260  }
261  }
262  return $this->pageCache[$uid];
263  }
264 
271  protected function ‪getAvailableLanguages(int $pageId): array
272  {
273  $languageOptions = [];
274  $translationConfigurationProvider = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
275  $systemLanguages = $translationConfigurationProvider->getSystemLanguages($pageId);
276 
277  if ($this->‪getBackendUser()->checkLanguageAccess(0)) {
278  // Use configured label for default language
279  $languageOptions[0] = $systemLanguages[0]['title'];
280  }
281 
282  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
283  ->getQueryBuilderForTable('pages');
284  $queryBuilder->getRestrictions()
285  ->removeAll()
286  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
287  ->add(GeneralUtility::makeInstance(WorkspaceRestriction::class, (int)$this->‪getBackendUser()->workspace));
288 
289  $result = $queryBuilder->select('sys_language_uid')
290  ->from('pages')
291  ->where(
292  $queryBuilder->expr()->eq(
293  ‪$GLOBALS['TCA']['pages']['ctrl']['transOrigPointerField'],
294  $queryBuilder->createNamedParameter($pageId, ‪Connection::PARAM_INT)
295  )
296  )
297  ->executeQuery();
298 
299  while ($row = $result->fetchAssociative()) {
300  $languageId = (int)$row['sys_language_uid'];
301  // Only add links to active languages the user has access to
302  if (isset($systemLanguages[$languageId]) && $this->‪getBackendUser()->‪checkLanguageAccess($languageId)) {
303  $languageOptions[$languageId] = $systemLanguages[$languageId]['title'];
304  }
305  }
306 
307  return $languageOptions;
308  }
309 
313  protected function ‪getBackendUser(): ‪BackendUserAuthentication
314  {
315  return ‪$GLOBALS['BE_USER'];
316  }
317 }
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\compilePreviewKeyword
‪string compilePreviewKeyword(int $ttl=172800, ?int $workspaceId=null)
Definition: PreviewUriBuilder.php:220
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\$pageCache
‪array $pageCache
Definition: PreviewUriBuilder.php:49
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\__construct
‪__construct(EventDispatcherInterface $eventDispatcher, WorkspaceService $workspaceService)
Definition: PreviewUriBuilder.php:63
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:49
‪TYPO3\CMS\Workspaces\Event\RetrievedPreviewUrlEvent
Definition: RetrievedPreviewUrlEvent.php:27
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\$workspaceService
‪WorkspaceService $workspaceService
Definition: PreviewUriBuilder.php:53
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\buildUriForWorkspaceSplitPreview
‪UriInterface buildUriForWorkspaceSplitPreview(int $uid)
Definition: PreviewUriBuilder.php:124
‪TYPO3\CMS\Core\Exception\SiteNotFoundException
Definition: SiteNotFoundException.php:25
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\$previewLinkLifetime
‪int $previewLinkLifetime
Definition: PreviewUriBuilder.php:61
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\buildUriForPage
‪string buildUriForPage(int $uid, int $languageId=0)
Definition: PreviewUriBuilder.php:77
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\getAvailableLanguages
‪array getAvailableLanguages(int $pageId)
Definition: PreviewUriBuilder.php:267
‪TYPO3\CMS\Backend\Routing\UriBuilder
Definition: UriBuilder.php:40
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder
Definition: PreviewUriBuilder.php:46
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\getBackendUser
‪BackendUserAuthentication getBackendUser()
Definition: PreviewUriBuilder.php:309
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\checkLanguageAccess
‪bool checkLanguageAccess($langValue)
Definition: BackendUserAuthentication.php:670
‪TYPO3\CMS\Core\Routing\InvalidRouteArgumentsException
Definition: InvalidRouteArgumentsException.php:25
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Workspaces\Service\WorkspaceService
Definition: WorkspaceService.php:36
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\createPreviewUriForElement
‪createPreviewUriForElement(string $table, int $uid, ?array $liveRecord=null, ?array $versionRecord=null)
Definition: PreviewUriBuilder.php:160
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:38
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\buildUriForElement
‪string buildUriForElement(string $table, int $uid, ?array $liveRecord=null, ?array $versionRecord=null)
Definition: PreviewUriBuilder.php:147
‪TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider
Definition: TranslationConfigurationProvider.php:37
‪TYPO3\CMS\Core\Utility\StringUtility\getUniqueId
‪static string getUniqueId($prefix='')
Definition: StringUtility.php:128
‪TYPO3\CMS\Workspaces\Service\WorkspaceService\getPreviewLinkLifetime
‪int getPreviewLinkLifetime()
Definition: WorkspaceService.php:100
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\$eventDispatcher
‪EventDispatcherInterface $eventDispatcher
Definition: PreviewUriBuilder.php:57
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction
Definition: DeletedRestriction.php:28
‪TYPO3\CMS\Backend\Routing\PreviewUriBuilder
Definition: PreviewUriBuilder.php:32
‪TYPO3\CMS\Workspaces\Preview
Definition: PreviewUriBuilder.php:18
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\buildUrisForAllLanguagesOfPage
‪array buildUrisForAllLanguagesOfPage(int $pageId)
Definition: PreviewUriBuilder.php:105
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:50
‪TYPO3\CMS\Backend\Routing\UriBuilder\ABSOLUTE_URL
‪const ABSOLUTE_URL
Definition: UriBuilder.php:44
‪TYPO3\CMS\Core\Utility\StringUtility
Definition: StringUtility.php:22
‪TYPO3\CMS\Workspaces\Preview\PreviewUriBuilder\getLivePageUid
‪int getLivePageUid(int $uid)
Definition: PreviewUriBuilder.php:248
‪TYPO3\CMS\Core\Database\Query\Restriction\WorkspaceRestriction
Definition: WorkspaceRestriction.php:40