eventDispatcher->dispatch( new BeforeJavaScriptsRenderingEvent($this->assetCollector, true, $priority) ); $template = '%source%'; $assets = $this->assetCollector->getInlineJavaScripts($priority); return $this->render($assets, $template, true, Directive::ScriptSrcElem, $nonce); } public function renderJavaScript($priority = false, ?ConsumableNonce $nonce = null): string { $this->eventDispatcher->dispatch( new BeforeJavaScriptsRenderingEvent($this->assetCollector, false, $priority) ); $template = ''; $assets = $this->assetCollector->getJavaScripts($priority); foreach ($assets as &$assetData) { // Collect CSP hash from original source path before URL transformation if (!empty($assetData['options']['csp'])) { $integrity = $assetData['attributes']['integrity'] ?? ''; if ($integrity !== '') { $this->directiveHashCollection->addGenericHashValue(Directive::ScriptSrcElem, $integrity); } else { $this->directiveHashCollection->addResourceHash(Directive::ScriptSrcElem, $assetData['source']); } } $assetData['source'] = $this->getAbsoluteWebPath($assetData['source']); $assetData['attributes']['src'] = $assetData['source']; } return $this->render($assets, $template, false, Directive::ScriptSrcElem, $nonce); } public function renderInlineStyleSheets($priority = false, ?ConsumableNonce $nonce = null): string { $this->eventDispatcher->dispatch( new BeforeStylesheetsRenderingEvent($this->assetCollector, true, $priority) ); $template = '%source%'; $assets = $this->assetCollector->getInlineStyleSheets($priority); return $this->render($assets, $template, true, Directive::StyleSrcElem, $nonce); } public function renderStyleSheets(bool $priority = false, string $endingSlash = '', ?ConsumableNonce $nonce = null): string { $this->eventDispatcher->dispatch( new BeforeStylesheetsRenderingEvent($this->assetCollector, false, $priority) ); $template = ''; $assets = $this->assetCollector->getStyleSheets($priority); foreach ($assets as &$assetData) { $originalSource = $assetData['source']; // Collect CSP hash from original source path before URL transformation if (!empty($assetData['options']['csp'])) { $integrity = $assetData['attributes']['integrity'] ?? ''; if ($integrity !== '') { $this->directiveHashCollection->addGenericHashValue(Directive::StyleSrcElem, $integrity); } else { $this->directiveHashCollection->addResourceHash(Directive::StyleSrcElem, $assetData['source']); } } $assetData['source'] = $this->getAbsoluteWebPath($assetData['source']); $assetData['attributes']['href'] = $assetData['source']; $assetData['attributes']['rel'] = $assetData['attributes']['rel'] ?? 'stylesheet'; if (($assetData['attributes']['integrity'] ?? '') === ResourceHashCollection::AUTO) { $hash = $this->resourceHashCollection->fetchResourceHash($originalSource)?->export() ?? ''; if ($hash !== '') { $assetData['attributes']['integrity'] = $hash; if (empty($assetData['attributes']['crossorigin']) && PathUtility::hasProtocolAndScheme($originalSource)) { $assetData['attributes']['crossorigin'] = 'anonymous'; } } else { unset($assetData['attributes']['integrity']); } } } return $this->render($assets, $template, false, Directive::StyleSrcElem, $nonce); } protected function render( array $assets, string $template, bool $isInline, Directive $directive, ?ConsumableNonce $nonce = null ): string { $results = []; foreach ($assets as $assetData) { $attributes = $assetData['attributes']; $useCsp = !empty($assetData['options']['csp']); if ($isInline && $useCsp) { $this->directiveHashCollection->addInlineHash($directive, $assetData['source']); } if ($nonce !== null && $useCsp) { $attributes['nonce'] = $isInline ? $nonce->consumeInline($directive) : $nonce->consumeStatic($directive); } $attributesString = count($attributes) ? ' ' . GeneralUtility::implodeAttributes($attributes, true) : ''; $results[] = str_replace( ['%attributes%', '%source%'], [$attributesString, $assetData['source']], $template ); } return implode(LF, $results); } private function getAbsoluteWebPath(string $file): string { $resource = $this->systemResourceFactory->createPublicResource($file); return (string)$this->resourcePublisher->generateUri($resource, null); } }