173 lines
7.3 KiB
PHP
173 lines
7.3 KiB
PHP
<?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\SystemResource\Publishing;
|
|
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use Psr\Http\Message\UriInterface;
|
|
use Symfony\Component\DependencyInjection\Attribute\AsAlias;
|
|
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
|
use TYPO3\CMS\Core\Core\Environment;
|
|
use TYPO3\CMS\Core\Http\NormalizedParams;
|
|
use TYPO3\CMS\Core\Messaging\FlashMessage;
|
|
use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
|
|
use TYPO3\CMS\Core\Package\Exception\PackageAssetsPublishingFailedException;
|
|
use TYPO3\CMS\Core\Package\PackageInterface;
|
|
use TYPO3\CMS\Core\SystemResource\Exception\CanNotGenerateUriException;
|
|
use TYPO3\CMS\Core\SystemResource\Publishing\FileSystem\FileSystemPublisherInterface;
|
|
use TYPO3\CMS\Core\SystemResource\Type\PublicResourceInterface;
|
|
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
|
|
/**
|
|
* This implementation publishes (when implemented) public assets from extension
|
|
* packages to the public _assets directory using a hash as directory name.
|
|
* Subsequently, it can also generate URIs to public resource objects within that _assets folder
|
|
*
|
|
* @internal Never use or reference it directly, use SystemResourcePublisherInterface to inject it (or a proper replacement).
|
|
*/
|
|
#[Autoconfigure(public: true), AsAlias(SystemResourcePublisherInterface::class, public: true)]
|
|
final readonly class DefaultSystemResourcePublisher implements SystemResourcePublisherInterface
|
|
{
|
|
private const string PUBLISHING_DIRECTORY = '_assets/';
|
|
private const string PUBLISHING_DIRECTORY_INSTALL = '_assets_install/';
|
|
|
|
/**
|
|
* @var FileSystemPublisherInterface[]
|
|
*/
|
|
private array $fileSystemPublishers;
|
|
|
|
private string $publishingDirectory;
|
|
|
|
public function __construct(
|
|
array $fileSystemPublishers = [],
|
|
bool $failsafe = false,
|
|
) {
|
|
$this->fileSystemPublishers = $fileSystemPublishers;
|
|
$this->publishingDirectory = $failsafe ? self::PUBLISHING_DIRECTORY_INSTALL : self::PUBLISHING_DIRECTORY;
|
|
}
|
|
|
|
public function publishResources(
|
|
PackageInterface $package,
|
|
): FlashMessageQueue {
|
|
$queue = new FlashMessageQueue('asset:publish');
|
|
$resourceDefinitions = $package
|
|
->getResources()
|
|
->getPublicResourceDefinitions();
|
|
|
|
foreach ($resourceDefinitions as $definition) {
|
|
$publishingContext = new ResourcePublishingContext(
|
|
package: $package,
|
|
definition: $definition,
|
|
);
|
|
if ($publishingContext->isSourcePublic) {
|
|
continue;
|
|
}
|
|
$publicResourcesPath = Environment::getPublicPath() . '/' . $this->publishingDirectory . $publishingContext->prefix;
|
|
GeneralUtility::mkdir_deep(dirname($publicResourcesPath));
|
|
try {
|
|
foreach ($this->fileSystemPublishers as $publisher) {
|
|
if (!$publisher->canPublish($publishingContext->filesystemPath, $publicResourcesPath)) {
|
|
continue;
|
|
}
|
|
if (is_file($publishingContext->filesystemPath)) {
|
|
$publisher->publishFile($publishingContext->filesystemPath, $publicResourcesPath);
|
|
} else {
|
|
if (!is_dir($publishingContext->filesystemPath)) {
|
|
$queue->addMessage(new FlashMessage(
|
|
sprintf(
|
|
'Did not publish public resource for extension "%s".'
|
|
. chr(10)
|
|
. 'The source file/directory "%s" does not exist.',
|
|
$package->getPackageKey(),
|
|
substr($publishingContext->filesystemPath, strlen(Environment::getProjectPath())),
|
|
),
|
|
$package->getPackageKey(),
|
|
ContextualFeedbackSeverity::INFO,
|
|
));
|
|
break;
|
|
}
|
|
$publisher->publishFolder($publishingContext->filesystemPath, $publicResourcesPath);
|
|
}
|
|
break;
|
|
}
|
|
} catch (PackageAssetsPublishingFailedException $e) {
|
|
$queue->addMessage(new FlashMessage(
|
|
sprintf(
|
|
'Could not publish public resources for extension "%s" by using the "%s" strategy.'
|
|
. chr(10)
|
|
. 'Check whether the target directory "%s" already exists'
|
|
. chr(10)
|
|
. 'and TYPO3 has permissions to write inside the "_assets" directory.',
|
|
$package->getPackageKey(),
|
|
$e->publishingStrategy,
|
|
'.' . substr($publicResourcesPath, strlen(Environment::getProjectPath())),
|
|
),
|
|
$package->getPackageKey(),
|
|
ContextualFeedbackSeverity::ERROR,
|
|
));
|
|
}
|
|
}
|
|
return $queue;
|
|
}
|
|
|
|
/**
|
|
* @throws CanNotGenerateUriException
|
|
*/
|
|
public function generateUri(PublicResourceInterface $publicResource, ?ServerRequestInterface $request, ?UriGenerationOptions $options = null): UriInterface
|
|
{
|
|
if (!$publicResource->isPublished()) {
|
|
throw new CanNotGenerateUriException(sprintf('Can not generate Uri for an unpublished resource %s', $publicResource), 1761211273);
|
|
}
|
|
$request ??= $GLOBALS['TYPO3_REQUEST'] ?? null;
|
|
$options ??= new UriGenerationOptions();
|
|
return $publicResource->getPublicUri(
|
|
new DefaultSystemResourceUriGenerator(
|
|
$this->publishingDirectory,
|
|
$this->extractPublicPrefixFromRequest($request, $options->uriPrefix),
|
|
$request,
|
|
$options,
|
|
)
|
|
);
|
|
}
|
|
|
|
private function extractPublicPrefixFromRequest(?ServerRequestInterface $request, ?string $publicPrefix): string
|
|
{
|
|
if ($publicPrefix !== null) {
|
|
return $publicPrefix;
|
|
}
|
|
if ($request === null) {
|
|
return '/';
|
|
}
|
|
$normalizedParams = $request->getAttribute('normalizedParams');
|
|
return $this->getFrontendUrlPrefix($request->getAttribute('frontend.typoscript')?->getConfigArray(), $normalizedParams)
|
|
?? $normalizedParams->getSitePath();
|
|
}
|
|
|
|
private function getFrontendUrlPrefix(?array $typoScriptConfigArray, NormalizedParams $normalizedParams): ?string
|
|
{
|
|
if ($typoScriptConfigArray === null) {
|
|
return null;
|
|
}
|
|
if ($typoScriptConfigArray['forceAbsoluteUrls'] ?? false) {
|
|
return $normalizedParams->getSiteUrl();
|
|
}
|
|
$absRefPrefix = trim($typoScriptConfigArray['absRefPrefix'] ?? '');
|
|
return $absRefPrefix === 'auto' ? $normalizedParams->getSitePath() : $absRefPrefix;
|
|
}
|
|
}
|