` instead. * * ``` * * ``` * * @see https://docs.typo3.org/permalink/t3viewhelper:typo3-fluid-uri-resource * @see https://docs.typo3.org/permalink/t3viewhelper:typo3-fluid-uri-image */ final class ResourceViewHelper extends AbstractViewHelper { public function __construct( private readonly SystemResourceFactory $systemResourceFactory, private readonly SystemResourcePublisherInterface $resourcePublisher, private readonly SystemResourceIdentifierFactory $resourceIdentifierFactory, ) {} public function initializeArguments(): void { $this->registerArgument('resource', 'object', 'The resource object given as argument or child'); $this->registerArgument('path', 'string', 'The path and filename of the resource (relative to Public resource directory of the extension).'); $this->registerArgument('extensionName', 'string', 'Target extension name. If not set, the current extension name will be used'); $this->registerArgument('absolute', 'bool', 'If set, an absolute URI is rendered', false, false); $this->registerArgument('useCacheBusting', 'bool', 'If set, the URI is rendered with a cache buster', false, true); } /** * Render the URI to the resource. The filename is used from child content. * * @return string The URI to the resource */ public function render(): string { $resource = $this->renderChildren(); if (!$resource instanceof PublicResourceInterface) { $resourceIdentifier = $this->resolveResourceIdentifier(); $resource = $this->systemResourceFactory->createPublicResource($resourceIdentifier); } $request = $this->resolveRequest(); if ($this->arguments['absolute'] && $request === null) { throw new \RuntimeException( 'ViewHelper f:uri.resource needs a Request object to generate absolute URLs,', 1758574774 ); } return (string)$this->resourcePublisher->generateUri( $resource, $request, new UriGenerationOptions( absoluteUri: $this->arguments['absolute'], cacheBusting: $this->arguments['useCacheBusting'], ), ); } /** * Explicitly set argument name to be used as content. */ public function getContentArgumentName(): string { return 'resource'; } /** * Resolves the extension path, either directly when possible, or from extension name and request */ private function resolveResourceIdentifier(): string { if (!isset($this->arguments['path'])) { throw new MissingArgumentException('ViewHelper f:uri.resource needs either "resource", or "path" argument to be set', 1759231234); } $path = $this->arguments['path']; try { return (string)$this->resourceIdentifierFactory->create($path); } catch (CanNotResolveSystemResourceIdentifierException) { $packageKey = $this->resolveExtensionKey(); $relativePath = 'Resources/Public/' . ltrim($path, '/'); return (string)$this->resourceIdentifierFactory->createFromPackagePath( $this->resolveExtensionKey(), 'Resources/Public/' . ltrim($path, '/'), sprintf('Uri\ResourceViewHelper, package key: "%s", relative path: "%s', $packageKey, $relativePath) ); } } /** * Resolves extension key either from given extension name argument or from request */ private function resolveExtensionKey(): string { $extensionName = $this->arguments['extensionName']; if ($extensionName === null) { return $this->resolveValidatedRequest($this->resolveRequest())->getControllerExtensionKey(); } return GeneralUtility::camelCaseToLowerCaseUnderscored($extensionName); } /** * Resolves the request from rendering context */ private function resolveRequest(): ?ServerRequestInterface { if ($this->renderingContext->hasAttribute(ServerRequestInterface::class)) { return $this->renderingContext->getAttribute(ServerRequestInterface::class); } return null; } /** * Resolves and validates the request from rendering context */ private function resolveValidatedRequest(?ServerRequestInterface $request): RequestInterface { if (!$request instanceof RequestInterface) { throw new \RuntimeException( sprintf( 'ViewHelper f:uri.resource needs an Extbase Request object to resolve extension name for given path "%s".' . ' If not in Extbase context, either set argument "extensionName",' . ' or (better) use the standard EXT: syntax for path attribute like \'path="EXT:indexed_search/Resources/Public/Icons/Extension.svg"\'.', $this->arguments['path'] ), 1639672666 ); } if ($request->getControllerExtensionKey() === '') { throw new \RuntimeException( sprintf( 'Can not resolve extension key for given path "%s".' . ' If not in Extbase context, either set argument "extensionName",' . ' or (better) use the standard EXT: syntax for path attribute like \'path="EXT:indexed_search/Resources/Public/Icons/Extension.svg"\'.', $this->arguments['path'] ), 1640097205 ); } return $request; } }