‪TYPO3CMS  ‪main
TypolinkSoftReferenceParser.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 TYPO3\CMS\Backend\Utility\BackendUtility;
25 use TYPO3\CMS\Core\LinkHandling\TypoLinkCodecService;
29 
36 {
37  protected EventDispatcherInterface ‪$eventDispatcher;
38 
39  public function ‪__construct(EventDispatcherInterface ‪$eventDispatcher)
40  {
41  $this->eventDispatcher = ‪$eventDispatcher;
42  }
43 
44  public function ‪parse(string $table, string $field, int ‪$uid, string $content, string $structurePath = ''): ‪SoftReferenceParserResult
45  {
46  $this->‪setTokenIdBasePrefix($table, (string)‪$uid, $field, $structurePath);
47 
48  // First, split the input string by a comma if the "linkList" parameter is set.
49  // An example: the link field for images in content elements of type "textpic" or "image". This field CAN be configured to define a link per image, separated by comma.
50  if (in_array('linkList', $this->parameters, true)) {
51  // Preserving whitespace on purpose.
52  $linkElement = explode(',', $content);
53  } else {
54  // If only one element, just set in this array to make it easy below.
55  $linkElement = [$content];
56  }
57  // Traverse the links now:
58  $elements = [];
59  foreach ($linkElement as $k => $typolinkValue) {
60  $tLP = $this->‪getTypoLinkParts($typolinkValue, $table, ‪$uid);
61  $linkElement[$k] = $this->‪setTypoLinkPartsElement($tLP, $elements, $typolinkValue, $k);
62  }
63 
65  implode(',', $linkElement),
66  $elements
67  );
68  }
69 
84  protected function ‪getTypoLinkParts(string $typolinkValue, string $referenceTable, int $referenceUid)
85  {
86  $finalTagParts = GeneralUtility::makeInstance(TypoLinkCodecService::class)->decode($typolinkValue);
87 
88  $link_param = $finalTagParts['url'];
89  // we define various keys below, "url" might be misleading
90  unset($finalTagParts['url']);
91 
92  if (stripos(rawurldecode(trim($link_param)), 'phar://') === 0) {
93  throw new \RuntimeException(
94  'phar scheme not allowed as soft reference target',
95  1530030672
96  );
97  }
98 
99  $linkService = GeneralUtility::makeInstance(LinkService::class);
100  try {
101  $linkData = $linkService->resolve($link_param);
102  switch ($linkData['type']) {
104  $referencePageId = $referenceTable === 'pages'
105  ? $referenceUid
106  : (int)(BackendUtility::getRecord($referenceTable, $referenceUid)['pid'] ?? 0);
107  if ($referencePageId) {
108  $pageTsConfig = BackendUtility::getPagesTSconfig($referencePageId);
109  $table = $pageTsConfig['TCEMAIN.']['linkHandler.'][$linkData['identifier'] . '.']['configuration.']['table'] ?? $linkData['identifier'];
110  } else {
111  // Backwards compatibility for the old behaviour, where the identifier was saved as the table.
112  $table = $linkData['identifier'];
113  }
114  $finalTagParts['table'] = $table;
115  $finalTagParts['uid'] = $linkData['uid'];
116  break;
118  $linkData['pageuid'] = (int)($linkData['pageuid'] ?? 0);
119  if (isset($linkData['pagetype'])) {
120  $linkData['pagetype'] = (int)$linkData['pagetype'];
121  }
122  if (isset($linkData['fragment'])) {
123  $finalTagParts['anchor'] = $linkData['fragment'];
124  }
125  break;
128  if (isset($linkData['file'])) {
129  $finalTagParts['type'] = ‪LinkService::TYPE_FILE;
130  $linkData['file'] = $linkData['file'] instanceof ‪FileInterface ? $linkData['file']->getUid() : $linkData['file'];
131  } else {
132  $pU = parse_url($link_param);
133  parse_str($pU['query'] ?? '', $query);
134  if (isset($query['uid'])) {
135  $finalTagParts['type'] = ‪LinkService::TYPE_FILE;
136  $finalTagParts['file'] = (int)$query['uid'];
137  }
138  }
139  break;
140  }
141  return array_merge($finalTagParts, $linkData);
142  } catch (‪UnknownLinkHandlerException $e) {
143  // Cannot handle anything
144  return $finalTagParts;
145  }
146  }
147 
158  protected function ‪setTypoLinkPartsElement($tLP, &$elements, $content, $idx)
159  {
160  // Initialize, set basic values. In any case a link will be shown
161  $tokenID = $this->‪makeTokenID('setTypoLinkPartsElement:' . $idx);
162  $elements[$tokenID . ':' . $idx] = [];
163  $elements[$tokenID . ':' . $idx]['matchString'] = $content;
164  // Based on link type, maybe do more:
165  switch ((string)($tLP['type'] ?? '')) {
167  // Mail addresses can be substituted manually:
168  $elements[$tokenID . ':' . $idx]['subst'] = [
169  'type' => 'string',
170  'tokenID' => $tokenID,
171  'tokenValue' => (string)($tLP['email'] ?? ''),
172  ];
173  // Output content will be the token instead:
174  $content = '{softref:' . $tokenID . '}';
175  break;
177  // phone number can be substituted manually:
178  $elements[$tokenID . ':' . $idx]['subst'] = [
179  'type' => 'string',
180  'tokenID' => $tokenID,
181  'tokenValue' => (string)($tLP['telephone'] ?? ''),
182  ];
183  // Output content will be the token instead:
184  $content = '{softref:' . $tokenID . '}';
185  break;
187  // URLs can be substituted manually
188  $elements[$tokenID . ':' . $idx]['subst'] = [
189  'type' => 'external',
190  'tokenID' => $tokenID,
191  'tokenValue' => (string)($tLP['url'] ?? ''),
192  ];
193  // Output content will be the token instead:
194  $content = '{softref:' . $tokenID . '}';
195  break;
197  // This is a link to a folder...
198  unset($elements[$tokenID . ':' . $idx]);
199  return $content;
201  // Process files referenced by their FAL uid
202  if (isset($tLP['file'])) {
203  $fileId = $tLP['file'] instanceof ‪FileInterface ? $tLP['file']->getUid() : $tLP['file'];
204  // Token and substitute value
205  $elements[$tokenID . ':' . $idx]['subst'] = [
206  'type' => 'db',
207  'recordRef' => 'sys_file:' . $fileId,
208  'tokenID' => $tokenID,
209  'tokenValue' => 'file:' . $fileId,
210  ];
211  // Output content will be the token instead:
212  $content = '{softref:' . $tokenID . '}';
213  } elseif ($tLP['identifier'] ?? false) {
214  $linkHandlerValue = explode(':', trim($tLP['identifier']), 2)[1];
215  if (‪MathUtility::canBeInterpretedAsInteger($linkHandlerValue)) {
216  // Token and substitute value
217  $elements[$tokenID . ':' . $idx]['subst'] = [
218  'type' => 'db',
219  'recordRef' => 'sys_file:' . $linkHandlerValue,
220  'tokenID' => $tokenID,
221  'tokenValue' => (string)$tLP['identifier'],
222  ];
223  // Output content will be the token instead:
224  $content = '{softref:' . $tokenID . '}';
225  } else {
226  // This is a link to a folder...
227  return $content;
228  }
229  } else {
230  return $content;
231  }
232  break;
234  // Rebuild page reference typolink part:
235  $content = '';
236  // Set page id:
237  if ($tLP['pageuid']) {
238  $content .= '{softref:' . $tokenID . '}';
239  $elements[$tokenID . ':' . $idx]['subst'] = [
240  'type' => 'db',
241  'recordRef' => 'pages:' . $tLP['pageuid'],
242  'tokenID' => $tokenID,
243  'tokenValue' => (string)$tLP['pageuid'],
244  ];
245  }
246  // Add type if applicable
247  if ((string)($tLP['pagetype'] ?? '') !== '') {
248  $content .= ',' . $tLP['pagetype'];
249  }
250  // Add anchor if applicable
251  if ((string)($tLP['anchor'] ?? '') !== '') {
252  // Anchor is assumed to point to a content elements:
253  if (‪MathUtility::canBeInterpretedAsInteger($tLP['anchor'])) {
254  // Initialize a new entry because we have a new relation:
255  $newTokenID = $this->‪makeTokenID('setTypoLinkPartsElement:anchor:' . $idx);
256  $elements[$newTokenID . ':' . $idx] = [];
257  $elements[$newTokenID . ':' . $idx]['matchString'] = 'Anchor Content Element: ' . $tLP['anchor'];
258  $content .= '#{softref:' . $newTokenID . '}';
259  $elements[$newTokenID . ':' . $idx]['subst'] = [
260  'type' => 'db',
261  'recordRef' => 'tt_content:' . $tLP['anchor'],
262  'tokenID' => $newTokenID,
263  'tokenValue' => (string)$tLP['anchor'],
264  ];
265  } else {
266  // Anchor is a hardcoded string
267  $content .= '#' . $tLP['anchor'];
268  }
269  }
270  break;
272  $elements[$tokenID . ':' . $idx]['subst'] = [
273  'type' => 'db',
274  'recordRef' => $tLP['table'] . ':' . $tLP['uid'],
275  'tokenID' => $tokenID,
276  'tokenValue' => (string)$content,
277  ];
278 
279  $content = '{softref:' . $tokenID . '}';
280  break;
281  default:
282  $event = new ‪AppendLinkHandlerElementsEvent($tLP, $content, $elements, $idx, $tokenID);
283  $this->eventDispatcher->dispatch($event);
284 
285  $elements = $event->getElements();
286  $tLP = $event->getLinkParts();
287  $content = $event->getContent();
288 
289  if (!$event->isResolved()) {
290  $elements[$tokenID . ':' . $idx]['error'] = 'Couldn\'t decide typolink mode.';
291  return $content;
292  }
293  }
294  // Finally, for all entries that was rebuild with tokens, add target, class, title and additionalParams in the end
295  $tLP['url'] = $content;
296  // Return rebuilt typolink value
297  return GeneralUtility::makeInstance(TypoLinkCodecService::class)->encode($tLP);
298  }
299 }
‪TYPO3\CMS\Core\DataHandling\SoftReference\AbstractSoftReferenceParser\setTokenIdBasePrefix
‪setTokenIdBasePrefix(string $table, string $uid, string $field, string $structurePath)
Definition: AbstractSoftReferenceParser.php:55
‪TYPO3\CMS\Core\Resource\FileInterface
Definition: FileInterface.php:26
‪TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserResult\create
‪static create(string $content, array $elements)
Definition: SoftReferenceParserResult.php:48
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:69
‪TYPO3\CMS\Core\DataHandling\SoftReference
Definition: AbstractSoftReferenceParser.php:18
‪TYPO3\CMS\Core\DataHandling\SoftReference\SoftReferenceParserResult
Definition: SoftReferenceParserResult.php:43
‪TYPO3\CMS\Webhooks\Message\$uid
‪identifier readonly int $uid
Definition: PageModificationMessage.php:35
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\DataHandling\SoftReference\AbstractSoftReferenceParser\makeTokenID
‪string makeTokenID(string $index='')
Definition: AbstractSoftReferenceParser.php:35
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\DataHandling\SoftReference\AbstractSoftReferenceParser
Definition: AbstractSoftReferenceParser.php:24