Feature: #109163 - Implement public system resources publishing
See forge#109163
Description
When implementing the new system resources API (Feature: #107537 - System resource API for system file access and public URI generation), resource publishing was skipped and is now implemented.
The most visible feature with this implementation is the now available
asset: command. This command can be executed to publish public extension
resources from their Resources/ folder to the document root directory
(public by default in Composer mode).
To maintain backwards compatibility for Composer mode installations, this command will
automatically be executed during composer install. This means after Composer has done
it's job installing packages, extension assets have already been published.
Public extension resources are however also published when extensions are set up
using extension: or when activating an extension in extension manager.
Because of this and because it might not be wanted or applicable
to publish assets on Composer build time, it is now possible to skip publishing
during composer install by setting the environment variable TYPO3_
e.g. like so: TYPO3_.
Not publishing assets on composer install will likely
become default in future TYPO3 versions.
TYPO3 only ships file system based publishing. From now on however, there is an additional strategy made available besides symlink publishing (*nix systems) and junction publishing (Windows systems). TYPO3 can now copy all files and folders from their private locations to the document root. This is handy for many use cases like container building, deployments with read only file systems, restrictive hosting environments and others.
By default the linking strategy is kept, especially for backwards compatibility reasons. It is however possible to influence the behaviour by setting the following configuration option:
Default behaviour: always link:
$GLOBALS
Always copy/ mirror files:
$GLOBALS
Copy/ mirror files in Production context and link folders in Development context:
$GLOBALS
Beyond file system publishing
While TYPO3 core only delivers file system based publishing, third party extensions can now implement other ways to publish public system resources.
By implementing
\TYPO3\
and registering the implementing class as alias of this interface, TYPO3 will use this not only
to publish system resources, but also to generate URIs to those, that reflect their new location,
e.g. on a CDN.
This will then work in TYPO3 classic mode as well, because publishing is now part of extension activation.
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Service;
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\Http\Uri;
use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
use TYPO3\CMS\Core\Package\PackageInterface;
use TYPO3\CMS\Core\SystemResource\Publishing\DefaultSystemResourcePublisher;
use TYPO3\CMS\Core\SystemResource\Publishing\SystemResourcePublisherInterface;
use TYPO3\CMS\Core\SystemResource\Publishing\UriGenerationOptions;
use TYPO3\CMS\Core\SystemResource\Type\PublicPackageFile;
use TYPO3\CMS\Core\SystemResource\Type\PublicResourceInterface;
#[Autoconfigure(public: true), AsAlias(SystemResourcePublisherInterface::class, public: true)]
final readonly class ExampleResourcePublisher implements SystemResourcePublisherInterface
{
private const CDN_URL = 'https://my.awsome.cdn/files/';
public function __construct(private DefaultSystemResourcePublisher $defaultSystemResourcePublisher)
{}
public function publishResources(PackageInterface $package): FlashMessageQueue
{
// There could be some additional logic here to publish files to a CDN
// For this example we assume the CDN loads the assets from the source
// automatically, so we publish as usual
return $this->defaultSystemResourcePublisher->publishResources($package);
}
public function generateUri(
PublicResourceInterface $publicResource,
?ServerRequestInterface $request,
?UriGenerationOptions $options = null
): UriInterface {
$defaultUri = $this->defaultSystemResourcePublisher->generateUri(
$publicResource,
$request,
new UriGenerationOptions(
uriPrefix: '',
absoluteUri: false,
cacheBusting: false,
),
);
if ($publicResource instanceof PublicPackageFile) {
return new Uri(self::CDN_URL . $defaultUri);
}
return $defaultUri;
}
}
Impact
There is no apparent impact for any TYPO3 installation, as changes made are mostly internal
and public API and behaviour is kept as before. Also for deployments there is nothing to
be changed, as asset publishing is still performed on composer install, but also
on extension: command, which both are obviously already part of any deployment workflow.
Users however now have more control when and how exactly publishing is performed, by setting
environment variable TYPO3_ for composer install or by configuring
mirror strategy for publishing by setting
$GLOBALS
in config/