Breaking: #110702 - Widened FAL processing task interfaces
See forge#110702
Description
TYPO3's File Abstraction Layer (FAL) processing pipeline - the
Task/
Abstract/
Processor/
Processor/
File classes that resize,
crop and convert images - has so far only ever operated on FAL files
(
\TYPO3\ and
\TYPO3\). The same pipeline now also
processes resources that are not backed by FAL - most commonly a system
resource shipped with a package and referenced via an
EXT:
/
PKG:
identifier - by routing a
Processed, or the new
\TYPO3\, through the same task/
processor machinery (see Feature: #110702 - Process system resource images). Several
signatures widened for this:
Tasknow returnsInterface:: get Source File () \TYPO3\instead ofCMS\ Core\ System Resource\ Type\ System Resource Interface \TYPO3\.CMS\ Core\ Resource\ File Tasknow returns the newInterface:: get Target File () \TYPO3\instead ofCMS\ Core\ Resource\ Processed Resource Interface \TYPO3\.CMS\ Core\ Resource\ Processed File Processednow implements this new interface, alongside the newFile Processedfor the non-FAL case.Resource AbstractandTask::__ construct () Tasknow take aType Registry:: get Task For Type () Processedinstead of aResource Interface Processed, and theFile Abstractproperty is now typedTask::$source File Systeminstead ofResource Interface File. A custom task class registered for a task type is constructed with aProcessedwhen the source is a system resource.Resource Processorno longer offers a task whose source is not a FALRegistry Fileto a processor unless that processor implements the new, opt-in\TYPO3\marker. TYPO3 Core'sCMS\ Core\ Resource\ Processing\ Resource Aware Processor Interface LocalandImage Processor Svgnow implement it and handle a non-FAL source for theImage Processor Image.task; no other Core processor does. As with any interface, a subclass inherits it: a custom processor extendingCrop Scale Mask LocalorImage Processor Svgis offered non-FAL tasks as well.Image Processor Filehas a new, last constructor argumentProcessing Service \TYPO3\.CMS\ Core\ Resource\ Processed Resource Cache Filenow acceptsProcessing Service:: process File () File(was|File Reference |System Resource Interface File), returns|File Reference Processed(wasFile |Processed Resource Processed), and itsFile $driverparameter is now nullable - a non-FAL resource is never fetched through aResourcedriver in the first place, so there is none to pass.Storage Before/File Processing Event Afterwiden the same way:File Processing Event getnow returnsDriver () ?Driver,Interface getreturnsFile () File, andInterface |System Resource Interface get/Processed File () setuseProcessed File () Processed.Resource Interface \TYPO3\now returnsCMS\ Core\ Imaging\ Image Resource:: get Original File () File(was|System Resource Interface |null ?File), andImagenow returnsResource:: get Processed File () ?Processed(wasResource Interface ?Processed). The correspondingFile with*methods and the constructor accept the same wider types. An image resource of a processed system resource carries the system resource and its() Processed.Resource
The URLs of
EXT:
/
PKG:
images rendered through image
processing change as well:
- A processed variant is no longer stored in
typo3temp/asassets/_ processed_/ csm_<name>_<hash>.<extension>, but intypo3temp/.assets/ images/ system/<hash>/<hash>-<hash>.<extension> - An image that does not need processing is linked by its own public URL,
as generated by the system resource publisher - including its cache
busting query string, for example
logo..png?1791262813 - The link generated by
imagefor such an image passes the system resource identifier asLink Wrap fileparameter to thetx_eID, instead of the uid of acms_ showpic sys_record.file
Impact
Custom
Processor/
Task/
Abstract
implementations, or PSR-14 listeners of the two events above, that use
get/
get/
get/
get/
get as a concrete
File
/
Processed/
Driver without a type check
- for example calling
get,
get,
get or any
Driver method directly - will
fail static analysis against the wider declared type, and can now
genuinely receive a system resource, or a
null
driver, at runtime:
a template or content element that references an
EXT:
/
PKG:
image is processed through this same pipeline starting with this release.
Custom task classes that type-hint the constructor argument as
Processed, or assign a
File
to
$source, fail
with a PHP fatal error. Code that instantiates
File manually, or extends it with its own
constructor, fails with an
Argument. Code relying on
Image/
get returning a
FAL object fails for an
EXT:
/
PKG:
image.
Tests, caches, CDN or proxy rules and other code that relied on the
previous URL pattern of processed
EXT:
/
PKG:
images no longer
match.
Affected installations
Installations with extensions that implement
Processor
directly, subclass
Local/
Svg,
Abstract or
File, listen to
Before/
After, or use
Image/
get, and rely
on the narrower pre-existing types without narrowing themselves.
Installations that depend on the URL of a processed
EXT:
/
PKG:
image.
Migration
Narrow the type before using
File
/
Processed/
Driver-specific members, the same way TYPO3 Core's own
processors do now:
use TYPO3\CMS\Core\Resource\File;
public function processTask(TaskInterface $task): void
{
$sourceFile = $task->getSourceFile();
if (!$sourceFile instanceof File) {
throw new \InvalidArgumentException('MyProcessor can only process a FAL File.', 1234567890);
}
// $sourceFile is now a concrete File again.
}
public function __invoke(AfterFileProcessingEvent $event): void
{
$driver = $event->getDriver();
if ($driver === null) {
// A non-FAL resource - nothing to do here, or handle it explicitly.
return;
}
// $driver is now a concrete DriverInterface again.
}
Custom task classes declare the constructor argument as
Processed, the same as
Abstract does.
A subclass of
Local or
Svg that
should only handle FAL files declines other tasks in
can:
use TYPO3\CMS\Core\Resource\File;
public function canProcessTask(TaskInterface $task): bool
{
return $task->getSourceFile() instanceof File
&& parent::canProcessTask($task);
}
Code that instantiates
File itself retrieves it
through dependency injection instead.
Check
Image/
get for
File
/
Processed before using FAL-specific methods.
Do not rely on the file name or location of a processed image.