File upload
Implementing file uploads / attachments to Extbase domain models has always been a bit of a challenge.
While it is straight-forward to access an existing file reference in a domain model, writing new files to the FAL (File Access Layer) takes more effort.
Accessing a file reference in an Extbase domain model
You need two components for the structural information: the Domain Model definition and the TCA entry.
The domain model definition:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Domain\Model;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
class Blog extends AbstractEntity
{
// A single file
protected ?FileReference $singleFile = null;
/**
* A collection of files.
* @var ObjectStorage<FileReference>
*/
protected ObjectStorage $multipleFiles;
// When using ObjectStorages, it is vital to initialize these.
public function __construct()
{
$this->multipleFiles = new ObjectStorage();
}
/**
* Called again with initialize object, as fetching an entity from the DB does not use the constructor
*/
public function initializeObject(): void
{
$this->multipleFiles = $this->multipleFiles ?? new ObjectStorage();
}
// Typical getters
public function getSingleFile(): ?FileReference
{
return $this->singleFile;
}
/**
* @return ObjectStorage|FileReference[]
*/
public function getMultipleFiles(): ObjectStorage
{
return $this->multipleFiles;
}
// For later examples, the setters:
public function setSingleFile(?FileReference $singleFile): void
{
$this->singleFile = $singleFile;
}
public function setMultipleFiles(ObjectStorage $files): void
{
$this->multipleFiles = $files;
}
}
and the TCA definition:
<?php
return [
'ctrl' => [
// .. usual TCA fields
],
'columns' => [
// ... usual TCA columns
'single_file' => [
'exclude' => true,
'label' => 'Single file',
'config' => [
'type' => 'file',
'maxitems' => 1,
'allowed' => 'common-image-types',
],
],
'multiple_files' => [
'exclude' => true,
'label' => 'Multiple files',
'config' => [
'type' => 'file',
'allowed' => 'common-image-types',
],
],
],
];
Once this is set up, you can create/edit records through the TYPO3 backend (for example via Web > List), attach a single or multiple files in it. Then using a normal controller and Fluid template, you can display an image.
The relevant Extbase controller part:
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\Controller;
use MyVendor\MyExtension\Domain\Model\Blog;
use MyVendor\MyExtension\Domain\Repository\BlogRepository;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
class BlogController extends ActionController
{
public function __construct(protected readonly BlogRepository $blogRepository)
{
// Note: The repository is a standard extbase repository, nothing specific
// to this example.
}
public function showAction(Blog $blog): ResponseInterface
{
$this->view->assign('blog', $blog);
return $this->htmlResponse();
}
}
and the corresponding Fluid template:
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
data-namespace-typo3-fluid="true">
<f:layout name="Default" />
<f:section name="main">
<p>Single image:</p>
<f:image image="{blog.singleFile.originalFile}" />
<p>Multiple images:</p>
<f:for each="{blog.multipleFiles}" as="image">
<f:image image="{image.originalFile}" />
</f:for>
<p>Access first image of multiple images:</p>
<f:image image="{blog.multipleFiles[0].originalFile}" />
</f:section>
On the PHP side within controllers, you can use the usual
$blog
and $blog
Extbase getters to retrieve the FileReference object.
Writing FileReference entries
Manual handling
Hint
With TYPO3 v13.3 Feature: #103511 - Introduce Extbase file upload and deletion handling was introduced and allows a simplified file upload handling. See Manual handling for details.
With TYPO3 versions 12.4 and below, attaching files to an Extbase domain model is possible by either:
-
Manually evaluating the
$_
data, process and validate the data, use raw QueryBuilder write actions onFILES sys_
andfile sys_
to persist the files quickly, or use at least some API methods:file_ reference <?php declare(strict_types=1); namespace MyVendor\MyExtension\Controller; use MyVendor\MyExtension\Domain\Model\Blog; use MyVendor\MyExtension\Domain\Repository\BlogRepository; use TYPO3\CMS\Core\Resource\DuplicationBehavior; use TYPO3\CMS\Core\Resource\ResourceFactory; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Core\Utility\StringUtility; use TYPO3\CMS\Extbase\Domain\Model\FileReference; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; class BlogController extends ActionController { public function __construct( protected ResourceFactory $resourceFactory, protected BlogRepository $blogRepository, ) {} public function attachFileUpload(Blog $blog): void { $falIdentifier = '1:/your_storage'; $yourFile = '/path/to/uploaded/file.jpg'; // Attach the file to the wanted storage $falFolder = $this->resourceFactory->retrieveFileOrFolderObject($falIdentifier); $fileObject = $falFolder->addFile( $yourFile, basename($yourFile), DuplicationBehavior::REPLACE, ); // Initialize a new storage object $newObject = [ 'uid_local' => $fileObject->getUid(), 'uid_foreign' => StringUtility::getUniqueId('NEW'), 'uid' => StringUtility::getUniqueId('NEW'), 'crop' => null, ]; // Create the FileReference Object $fileReference = $this->resourceFactory->createFileReferenceObject($newObject); // Port the FileReference Object to an Extbase FileReference $fileReferenceObject = GeneralUtility::makeInstance(FileReference::class); $fileReferenceObject->setOriginalResource($fileReference); // Persist the created file reference object to our Blog model $blog->setSingleFile($fileReferenceObject); $this->blogRepository->update($blog); // Note: For multiple files, a wrapping ObjectStorage would be needed } }
Instead of raw access to
$_
, starting with TYPO3 v12 the recommendation is to utilize the UploadedFile objects instead of $_FILES. In that case, validators can be used for custom UploadedFile objects to specify restrictions on file types, file sizes and image dimensions.FILES - Using (or better: adapting) a more complex implementation by using Extbase TypeConverters, as provided by Helmut Hummel's EXT:upload_example. This extension is no longer maintained and will not work without larger adaptation for TYPO3 v12 compatibility.