TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Core\LinkHandling;
|
||||
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use TYPO3\CMS\Core\LinkHandling\Event\AfterLinkResolvedByStringRepresentationEvent;
|
||||
use TYPO3\CMS\Core\LinkHandling\Exception\UnknownLinkHandlerException;
|
||||
use TYPO3\CMS\Core\LinkHandling\Exception\UnknownUrnException;
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
/**
|
||||
* Class responsible to find what kind of resource (type) is used
|
||||
* to link to (email, external url, file, page etc)
|
||||
* with the possibility to get a system-wide understandable "urn" to identify
|
||||
* what type it actually is, based on the scheme or prefix.
|
||||
*/
|
||||
class LinkService implements SingletonInterface
|
||||
{
|
||||
public const TYPE_PAGE = 'page';
|
||||
public const TYPE_INPAGE = 'inpage';
|
||||
public const TYPE_URL = 'url';
|
||||
public const TYPE_EMAIL = 'email';
|
||||
public const TYPE_TELEPHONE = 'telephone';
|
||||
public const TYPE_FILE = 'file';
|
||||
public const TYPE_FOLDER = 'folder';
|
||||
public const TYPE_RECORD = 'record';
|
||||
public const TYPE_UNKNOWN = 'unknown';
|
||||
|
||||
/**
|
||||
* All registered LinkHandlers
|
||||
*
|
||||
* @var LinkHandlingInterface[]
|
||||
*/
|
||||
protected $handlers;
|
||||
|
||||
/**
|
||||
* LinkService constructor initializes the registered handlers.
|
||||
*/
|
||||
public function __construct(
|
||||
protected readonly EventDispatcherInterface $eventDispatcher,
|
||||
) {
|
||||
$registeredLinkHandlers = $GLOBALS['TYPO3_CONF_VARS']['SYS']['linkHandler'] ?? [];
|
||||
$registeredLinkHandlers = is_array($registeredLinkHandlers) ? $registeredLinkHandlers : [];
|
||||
/** @var array<string,class-string> $registeredLinkHandlers */
|
||||
if ($registeredLinkHandlers !== []) {
|
||||
foreach ($registeredLinkHandlers as $type => $handlerClassName) {
|
||||
if (!isset($this->handlers[$type]) || !is_object($this->handlers[$type])) {
|
||||
$handler = GeneralUtility::makeInstance($handlerClassName);
|
||||
if ($handler instanceof LinkHandlingInterface) {
|
||||
$this->handlers[$type] = $handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Part of the typolink construction functionality, called by typoLink()
|
||||
* Used to resolve "legacy"-based typolinks and URNs.
|
||||
*
|
||||
* Tries to get the type of the link from the link parameter
|
||||
* could be
|
||||
* - "mailto" an email address
|
||||
* - "url" external URL
|
||||
* - "file" a local file (checked AFTER getPublicUrl() is called)
|
||||
* - "page" a page (integer)
|
||||
*
|
||||
* Does NOT check if the page exists or the file exists.
|
||||
*
|
||||
* @param string $linkParameter could be "fileadmin/myfile.jpg", "info@typo3.org", "13" or "http://www.typo3.org"
|
||||
*/
|
||||
public function resolve(string $linkParameter): array
|
||||
{
|
||||
try {
|
||||
// Check if the new syntax with "t3://" is used
|
||||
return $this->resolveByStringRepresentation($linkParameter);
|
||||
} catch (UnknownUrnException $e) {
|
||||
$legacyLinkNotationConverter = GeneralUtility::makeInstance(LegacyLinkNotationConverter::class);
|
||||
return $legacyLinkNotationConverter->resolve($linkParameter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with data interpretation of the link target, something like t3://page?uid=23.
|
||||
*
|
||||
* @throws Exception\UnknownLinkHandlerException
|
||||
* @throws Exception\UnknownUrnException
|
||||
*/
|
||||
public function resolveByStringRepresentation(string $urn): array
|
||||
{
|
||||
$result = [];
|
||||
$resolveException = null;
|
||||
try {
|
||||
// linking to any t3:// syntax
|
||||
if (stripos($urn, 't3://') === 0) {
|
||||
// lets parse the urn
|
||||
$urnParsed = parse_url($urn);
|
||||
$type = $urnParsed['host'];
|
||||
if (isset($urnParsed['query'])) {
|
||||
parse_str(htmlspecialchars_decode($urnParsed['query']), $data);
|
||||
} else {
|
||||
$data = [];
|
||||
}
|
||||
$fragment = $urnParsed['fragment'] ?? null;
|
||||
|
||||
if (isset($this->handlers[$type])) {
|
||||
$result = $this->handlers[$type]->resolveHandlerData($data);
|
||||
$result['type'] = $type;
|
||||
} else {
|
||||
$resolveException = new UnknownLinkHandlerException('LinkHandler for ' . $type . ' was not registered', 1460581769);
|
||||
}
|
||||
// this was historically named "section"
|
||||
if ($fragment) {
|
||||
$result['fragment'] = $fragment;
|
||||
}
|
||||
} elseif (($this->handlers[self::TYPE_URL] ?? false) && PathUtility::hasProtocolAndScheme($urn)) {
|
||||
$result = $this->handlers[self::TYPE_URL]->resolveHandlerData(['url' => $urn]);
|
||||
$result['type'] = self::TYPE_URL;
|
||||
} elseif (($this->handlers[self::TYPE_EMAIL] ?? false) && str_starts_with(strtolower($urn), 'mailto:')) {
|
||||
$result = $this->handlers[self::TYPE_EMAIL]->resolveHandlerData(['email' => $urn]);
|
||||
$result['type'] = self::TYPE_EMAIL;
|
||||
} elseif (($this->handlers[self::TYPE_TELEPHONE] ?? false) && str_starts_with(strtolower($urn), 'tel:')) {
|
||||
$result = $this->handlers[self::TYPE_TELEPHONE]->resolveHandlerData(['telephone' => $urn]);
|
||||
$result['type'] = self::TYPE_TELEPHONE;
|
||||
}
|
||||
} finally {
|
||||
$result = $this->eventDispatcher->dispatch(
|
||||
new AfterLinkResolvedByStringRepresentationEvent(
|
||||
result: $result,
|
||||
urn: $urn,
|
||||
resolveException: $resolveException
|
||||
)
|
||||
)->getResult();
|
||||
|
||||
if (empty($result['type'])) {
|
||||
// In case no link type could be resolved and UnknownLinkHandlerException
|
||||
// has been added before, throw the exception now to inform calling components.
|
||||
if ($resolveException === null) {
|
||||
// Use the general UnknownUrnException in case neither a defined
|
||||
// handler nor an event listener could resolve the given URN.
|
||||
$resolveException = new UnknownUrnException('No valid URN to resolve found', 1457177667);
|
||||
}
|
||||
|
||||
throw $resolveException;
|
||||
}
|
||||
}
|
||||
|
||||
// @todo If resolved result (linkDetails) are later used to build an uri using LinkBuilder->build(), it's needed
|
||||
// to have the original $linkParameter in the result array. Otherwise, places may break like e.g. the
|
||||
// DatabaseRecordLinkBuilder. Can we safely set this here directly and avoiding calls before build like
|
||||
// "$linkDetails['typoLinkParameter'] = $redirectTarget;" - e.g. like in the ext:redirects
|
||||
// TYPO3\CMS\Redirects\Service\RedirectService::resolveLinkDetailsFromLinkTarget() and other places.
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string interpretation of the link target, something like
|
||||
*
|
||||
* - t3://page?uid=23&my=value#cool
|
||||
* - https://www.typo3.org/
|
||||
* - t3://file?uid=13
|
||||
* - t3://folder?storage=2&identifier=/my/folder/
|
||||
* - mailto:mac@safe.com
|
||||
*
|
||||
* @param array $parameters
|
||||
* @throws Exception\UnknownLinkHandlerException
|
||||
*/
|
||||
public function asString(array $parameters): string
|
||||
{
|
||||
$linkHandler = $this->handlers[$parameters['type']] ?? null;
|
||||
if ($linkHandler !== null) {
|
||||
return $this->handlers[$parameters['type']]->asString($parameters);
|
||||
}
|
||||
if (isset($parameters['url']) && !empty($parameters['url'])) {
|
||||
// This usually happens for tel: or other types where a URL is available and the
|
||||
// legacy link service could resolve at least something
|
||||
return $parameters['url'];
|
||||
}
|
||||
throw new UnknownLinkHandlerException('No valid handlers found for type: ' . $parameters['type'], 1460629247);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user