TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?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 TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Http\ApplicationType;
|
||||
use TYPO3\CMS\Core\Http\Uri;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\SystemResource\Exception\CanNotGenerateUriException;
|
||||
use TYPO3\CMS\Core\SystemResource\Http\CacheBustingUri;
|
||||
|
||||
/**
|
||||
* This is tightly coupled to DefaultSystemResourcePublisher and acts
|
||||
* as a helper to actually generate the URI for a public resource.
|
||||
* This helper and its interface only exists to not expose the absolute
|
||||
* path from the system resource objects directly.
|
||||
*
|
||||
* @internal Only to be used in TYPO3\CMS\Core\SystemResource namespace
|
||||
*/
|
||||
readonly class DefaultSystemResourceUriGenerator implements SystemResourceUriGeneratorInterface
|
||||
{
|
||||
public function __construct(
|
||||
private string $publishingDirectory,
|
||||
private string $prefix,
|
||||
private ?ServerRequestInterface $request,
|
||||
private UriGenerationOptions $options,
|
||||
) {}
|
||||
|
||||
public function generateForPackageResource(
|
||||
ResourceUriBuildingContext $context,
|
||||
): UriInterface {
|
||||
$uri = $this->makeAbsolute(new Uri($this->calculateUriPath($context)));
|
||||
if (!$this->options->cacheBusting) {
|
||||
return $uri;
|
||||
}
|
||||
return CacheBustingUri::fromFileSystemPath(
|
||||
$context->absoluteResourcePath,
|
||||
$uri,
|
||||
$this->request ? ApplicationType::fromRequest($this->request) : null
|
||||
);
|
||||
}
|
||||
|
||||
public function generateForFile(File $file): UriInterface
|
||||
{
|
||||
$publicUrl = $file->getPublicUrl();
|
||||
if ($publicUrl === null) {
|
||||
throw new CanNotGenerateUriException(sprintf('Can not create a public Uri for a file %s', $file), 1758619473);
|
||||
}
|
||||
if (Environment::isCli()) {
|
||||
// On CLI FAL public URLs are always relative to public directory,
|
||||
// so we apply the prefix here, which is likely a "/" only,
|
||||
// unless calling code properly faked a request.
|
||||
$publicUrl = $this->prefix . $publicUrl;
|
||||
}
|
||||
$uri = $this->makeAbsolute(new Uri($publicUrl));
|
||||
if (!$this->options->cacheBusting) {
|
||||
return $uri;
|
||||
}
|
||||
return CacheBustingUri::fromFile(
|
||||
$file,
|
||||
$uri,
|
||||
);
|
||||
}
|
||||
|
||||
private function makeAbsolute(UriInterface $uri): UriInterface
|
||||
{
|
||||
if ($this->request === null || !$this->options->absoluteUri) {
|
||||
return $uri;
|
||||
}
|
||||
if ($uri->getHost() !== '') {
|
||||
return $uri;
|
||||
}
|
||||
$siteUri = new Uri($this->request->getAttribute('normalizedParams')->getSiteUrl());
|
||||
return $uri->withScheme($siteUri->getScheme())
|
||||
->withUserInfo($siteUri->getUserInfo())
|
||||
->withHost($siteUri->getHost())
|
||||
->withPort($siteUri->getPort());
|
||||
}
|
||||
|
||||
private function calculateUriPath(ResourceUriBuildingContext $context): string
|
||||
{
|
||||
if ($context->isSourcePublic) {
|
||||
return $this->prefix . substr($context->absoluteResourcePath, strlen(Environment::getPublicPath()) + 1);
|
||||
}
|
||||
return $this->prefix . $this->publishingDirectory . $context->uriPath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?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\FileSystem;
|
||||
|
||||
use TYPO3\CMS\Core\Package\Exception\PackageAssetsPublishingFailedException;
|
||||
|
||||
/**
|
||||
* @internal Only to be used in TYPO3\CMS\Core\SystemResource namespace
|
||||
*/
|
||||
interface FileSystemPublisherInterface
|
||||
{
|
||||
public function canPublish(string $source, string $target): bool;
|
||||
|
||||
/**
|
||||
* @throws PackageAssetsPublishingFailedException
|
||||
*/
|
||||
public function publishFolder(string $source, string $target): void;
|
||||
|
||||
/**
|
||||
* @throws PackageAssetsPublishingFailedException
|
||||
*/
|
||||
public function publishFile(string $source, string $target): void;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?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\FileSystem;
|
||||
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Package\Exception\PackageAssetsPublishingFailedException;
|
||||
use TYPO3\CMS\Core\Utility\File\FileSystem;
|
||||
|
||||
/**
|
||||
* @internal Only to be used in TYPO3\CMS\Core\SystemResource namespace
|
||||
*/
|
||||
final readonly class JunctionPublisher implements FileSystemPublisherInterface
|
||||
{
|
||||
private PublishingConfiguration $config;
|
||||
|
||||
public function __construct(private FileSystem $fileSystem)
|
||||
{
|
||||
$this->config = new PublishingConfiguration();
|
||||
}
|
||||
|
||||
public function canPublish(string $source, string $target): bool
|
||||
{
|
||||
return Environment::isWindows()
|
||||
&& $this->config->isLinkPublishingEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws PackageAssetsPublishingFailedException
|
||||
*/
|
||||
public function publishFolder(string $source, string $target): void
|
||||
{
|
||||
$this->ensureJunctionExists($source, $target);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \LogicException
|
||||
*/
|
||||
public function publishFile(string $source, string $target): void
|
||||
{
|
||||
throw new \LogicException(self::class . ' can not be used to publish single files', 1772535297);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws PackageAssetsPublishingFailedException
|
||||
*/
|
||||
private function ensureJunctionExists(string $target, string $junction): void
|
||||
{
|
||||
$e = null;
|
||||
if (!$this->fileSystem->isJunction($junction)) {
|
||||
try {
|
||||
$this->fileSystem->junction($target, $junction);
|
||||
} catch (IOException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($e !== null || realpath($target) !== realpath($junction)) {
|
||||
throw new PackageAssetsPublishingFailedException(
|
||||
'junction',
|
||||
1717488535,
|
||||
$e,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?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\FileSystem;
|
||||
|
||||
use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
|
||||
use TYPO3\CMS\Core\Package\Exception\PackageAssetsPublishingFailedException;
|
||||
|
||||
/**
|
||||
* @internal Only to be used in TYPO3\CMS\Core\SystemResource namespace
|
||||
*/
|
||||
final readonly class MirrorPublisher implements FileSystemPublisherInterface
|
||||
{
|
||||
private PublishingConfiguration $config;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = new PublishingConfiguration();
|
||||
}
|
||||
|
||||
public function canPublish(string $source, string $target): bool
|
||||
{
|
||||
return $this->config->isMirrorPublishingEnabled();
|
||||
}
|
||||
|
||||
public function publishFolder(string $source, string $target): void
|
||||
{
|
||||
if (realpath($source) === realpath($target)) {
|
||||
throw new PackageAssetsPublishingFailedException(
|
||||
'mirror',
|
||||
1773140314,
|
||||
);
|
||||
}
|
||||
$symfonyFilesystem = new SymfonyFilesystem();
|
||||
$symfonyFilesystem->mirror(
|
||||
$source,
|
||||
$target,
|
||||
null,
|
||||
[
|
||||
'delete' => true,
|
||||
'override' => true,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
public function publishFile(string $source, string $target): void
|
||||
{
|
||||
if (!is_file($source)) {
|
||||
throw new \LogicException('Can not publish file, because source is not a file', 1772538042);
|
||||
}
|
||||
if (realpath($source) === realpath($target)) {
|
||||
throw new PackageAssetsPublishingFailedException(
|
||||
'mirror',
|
||||
1773140294,
|
||||
);
|
||||
}
|
||||
$symfonyFilesystem = new SymfonyFilesystem();
|
||||
$symfonyFilesystem->copy($source, $target, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?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\FileSystem;
|
||||
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
|
||||
/**
|
||||
* @internal Only to be used in TYPO3\CMS\Core\SystemResource namespace
|
||||
*/
|
||||
final readonly class PublishingConfiguration
|
||||
{
|
||||
private string $publishingType;
|
||||
|
||||
public function __construct(?string $publishingType = null)
|
||||
{
|
||||
$publishingType = $publishingType ?? $GLOBALS['TYPO3_CONF_VARS']['SYS']['SystemResources']['filesystemPublishingType'] ?? 'auto';
|
||||
if ($publishingType === 'auto') {
|
||||
$publishingType = Environment::getContext()->isDevelopment() ? 'link' : 'mirror';
|
||||
}
|
||||
$this->publishingType = $publishingType;
|
||||
}
|
||||
|
||||
public function isLinkPublishingEnabled(): bool
|
||||
{
|
||||
return $this->publishingType === 'link';
|
||||
}
|
||||
|
||||
public function isMirrorPublishingEnabled(): bool
|
||||
{
|
||||
return $this->publishingType === 'mirror';
|
||||
}
|
||||
|
||||
public function hasCustomPublishingType(): bool
|
||||
{
|
||||
return !$this->isMirrorPublishingEnabled() && !$this->isLinkPublishingEnabled();
|
||||
}
|
||||
|
||||
public function getCustomPublishingType(): string
|
||||
{
|
||||
if (!$this->hasCustomPublishingType()) {
|
||||
throw new \LogicException('There is no custom publishing type enabled', 1773138713);
|
||||
}
|
||||
return $this->publishingType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?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\FileSystem;
|
||||
|
||||
use TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Package\Exception\PackageAssetsPublishingFailedException;
|
||||
use TYPO3\CMS\Core\Utility\File\FileSystem;
|
||||
|
||||
/**
|
||||
* @internal Only to be used in TYPO3\CMS\Core\SystemResource namespace
|
||||
*/
|
||||
final readonly class SymlinkPublisher implements FileSystemPublisherInterface
|
||||
{
|
||||
private PublishingConfiguration $config;
|
||||
|
||||
public function __construct(private FileSystem $fileSystem)
|
||||
{
|
||||
$this->config = new PublishingConfiguration();
|
||||
}
|
||||
|
||||
public function canPublish(string $source, string $target): bool
|
||||
{
|
||||
return !Environment::isWindows()
|
||||
&& $this->config->isLinkPublishingEnabled();
|
||||
}
|
||||
|
||||
public function publishFolder(string $source, string $target): void
|
||||
{
|
||||
$this->ensureSymlinkExists($source, $target, 'dir');
|
||||
}
|
||||
|
||||
public function publishFile(string $source, string $target): void
|
||||
{
|
||||
$this->ensureSymlinkExists($source, $target, 'file');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws PackageAssetsPublishingFailedException
|
||||
*/
|
||||
private function ensureSymlinkExists(string $target, string $link, string $type): void
|
||||
{
|
||||
$success = true;
|
||||
if (!$this->isSymlinked($link, $type)) {
|
||||
$success = $this->fileSystem->relativeSymlink($target, $link);
|
||||
}
|
||||
$this->ensureIsValid($target, $link, $success);
|
||||
}
|
||||
|
||||
private function isSymlinked(string $link, string $type): bool
|
||||
{
|
||||
return match ($type) {
|
||||
'file' => $this->fileSystem->isSymlinkedFile($link),
|
||||
'dir' => $this->fileSystem->isSymlinkedDirectory($link),
|
||||
default => throw new \UnexpectedValueException(sprintf('Type can only be "file" or "dir", "%s" given.', $type), 1774611766),
|
||||
};
|
||||
}
|
||||
|
||||
private function ensureIsValid(string $target, string $link, bool $success): void
|
||||
{
|
||||
if (!$success || realpath($target) !== realpath($link)) {
|
||||
throw new PackageAssetsPublishingFailedException(
|
||||
'symlink',
|
||||
1717488536,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?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 TYPO3\CMS\Core\Core\Environment;
|
||||
use TYPO3\CMS\Core\Package\PackageInterface;
|
||||
use TYPO3\CMS\Core\Package\Resource\Definition\DynamicPublicPrefixInterface;
|
||||
use TYPO3\CMS\Core\Package\Resource\Definition\PublicResourceDefinition;
|
||||
|
||||
/**
|
||||
* @internal Only to be used in TYPO3\CMS\Core\SystemResource namespace
|
||||
*/
|
||||
final readonly class ResourcePublishingContext
|
||||
{
|
||||
public string $prefix;
|
||||
public bool $isSourcePublic;
|
||||
public string $filesystemPath;
|
||||
|
||||
/**
|
||||
* Variable names are explicitly public API
|
||||
* for named variable access
|
||||
*/
|
||||
public function __construct(
|
||||
private PackageInterface $package,
|
||||
private PublicResourceDefinition $definition,
|
||||
) {
|
||||
$this->prefix = $definition->getPublicPrefix() instanceof DynamicPublicPrefixInterface
|
||||
? $definition->getPublicPrefix()->calculatePrefix($package, $definition)
|
||||
: $definition->getPublicPrefix();
|
||||
$this->isSourcePublic = str_starts_with($this->package->getPackagePath() . $this->definition->getRelativePath(), Environment::getPublicPath());
|
||||
$this->filesystemPath = $package->getPackagePath() . $definition->getRelativePath();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?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 TYPO3\CMS\Core\Package\PackageInterface;
|
||||
use TYPO3\CMS\Core\Package\Resource\Definition\PublicResourceDefinition;
|
||||
use TYPO3\CMS\Core\SystemResource\Type\PublicPackageFile;
|
||||
|
||||
/**
|
||||
* @internal Only to be used in TYPO3\CMS\Core\SystemResource namespace
|
||||
*/
|
||||
final readonly class ResourceUriBuildingContext
|
||||
{
|
||||
public string $absoluteResourcePath;
|
||||
public string $uriPath;
|
||||
public bool $isSourcePublic;
|
||||
|
||||
/**
|
||||
* Variable names are explicitly public API
|
||||
* for named variable access
|
||||
*/
|
||||
public function __construct(
|
||||
public PublicPackageFile $resource,
|
||||
public PackageInterface $package,
|
||||
public PublicResourceDefinition $definition,
|
||||
) {
|
||||
$this->absoluteResourcePath = $this->package->getPackagePath() . $this->resource->getRelativePath();
|
||||
$publishingContext = new ResourcePublishingContext(
|
||||
package: $package,
|
||||
definition: $definition
|
||||
);
|
||||
$this->isSourcePublic = $publishingContext->isSourcePublic;
|
||||
$this->uriPath = $publishingContext->prefix . substr($this->resource->getRelativePath(), strlen($this->definition->getRelativePath()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?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 TYPO3\CMS\Core\Messaging\FlashMessageQueue;
|
||||
use TYPO3\CMS\Core\Package\PackageInterface;
|
||||
use TYPO3\CMS\Core\SystemResource\Type\PublicResourceInterface;
|
||||
|
||||
/**
|
||||
* Implementations of this interface can publish public extension resources (once implemented)
|
||||
* and therefore also generate URIs to those published resources.
|
||||
* E.g. publish resources directly to a CDN and then generate CDS URIs
|
||||
* to those resources.
|
||||
*/
|
||||
interface SystemResourcePublisherInterface
|
||||
{
|
||||
public function publishResources(PackageInterface $package): FlashMessageQueue;
|
||||
|
||||
public function generateUri(PublicResourceInterface $publicResource, ?ServerRequestInterface $request, ?UriGenerationOptions $options = null): UriInterface;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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\UriInterface;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
|
||||
/**
|
||||
* This is an implementation detail to allow not exposing the absolute file path
|
||||
* to extension resources directly, but only to the resource publisher
|
||||
* when generating URLs to the _assets directory.
|
||||
*
|
||||
* @internal Only to be used in TYPO3\CMS\Core\SystemResource namespace
|
||||
*/
|
||||
interface SystemResourceUriGeneratorInterface
|
||||
{
|
||||
public function generateForPackageResource(
|
||||
ResourceUriBuildingContext $context,
|
||||
): UriInterface;
|
||||
public function generateForFile(File $file): UriInterface;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* Options for system resource URI generation.
|
||||
* These might change, by adding more options,
|
||||
* which means the variable names MUST be kept
|
||||
* (or properly deprecated) as they are public API.
|
||||
* Also, this object MUST be crated using named arguments.
|
||||
*/
|
||||
final readonly class UriGenerationOptions
|
||||
{
|
||||
/**
|
||||
* Variable names are explicitly public API
|
||||
* for named variable access
|
||||
*
|
||||
* Some or all of these options might to be applicable
|
||||
* to specific implementations SystemResourcePublisherInterface,
|
||||
* which means, that if other resource publishing strategies
|
||||
* are configured, that changing these options might not
|
||||
* influence the resulting URI
|
||||
*/
|
||||
public function __construct(
|
||||
public ?string $uriPrefix = null,
|
||||
public bool $absoluteUri = false,
|
||||
public bool $cacheBusting = true,
|
||||
) {}
|
||||
}
|
||||
Reference in New Issue
Block a user