TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,450 @@
|
||||
<?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\Resource;
|
||||
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\MathUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
/**
|
||||
* Abstract file representation in the file abstraction layer.
|
||||
*/
|
||||
abstract class AbstractFile implements FileInterface
|
||||
{
|
||||
/**
|
||||
* Various file properties
|
||||
*
|
||||
* Note that all properties, which only the persisted (indexed) files have are stored in this
|
||||
* overall properties array only. The only properties which really exist as object properties of
|
||||
* the file object are the storage, the identifier, the fileName and the indexing status.
|
||||
*
|
||||
* @var array<non-empty-string, mixed>
|
||||
*/
|
||||
protected array $properties = [];
|
||||
|
||||
/**
|
||||
* The storage this file is located in
|
||||
*/
|
||||
protected ?ResourceStorage $storage = null;
|
||||
|
||||
/**
|
||||
* The file name of this file
|
||||
*/
|
||||
protected string $name = '';
|
||||
|
||||
/**
|
||||
* If set to true, this file is regarded as being deleted.
|
||||
*/
|
||||
protected bool $deleted = false;
|
||||
|
||||
/******************
|
||||
* VARIOUS FILE PROPERTY GETTERS
|
||||
******************/
|
||||
/**
|
||||
* Returns true if the given property key exists for this file.
|
||||
*
|
||||
* @param non-empty-string $key
|
||||
*/
|
||||
public function hasProperty(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a property value
|
||||
*
|
||||
* @param non-empty-string $key
|
||||
*/
|
||||
public function getProperty(string $key): mixed
|
||||
{
|
||||
if ($this->hasProperty($key)) {
|
||||
return $this->properties[$key];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the properties of this object.
|
||||
*
|
||||
* @return array<non-empty-string, mixed>
|
||||
*/
|
||||
public function getProperties(): array
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getHashedIdentifier(): string
|
||||
{
|
||||
return $this->properties['identifier_hash'];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
// Do not check if file has been deleted because we might need the
|
||||
// name for undeleting it.
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the basename (the name without extension) of this file.
|
||||
*/
|
||||
public function getNameWithoutExtension(): string
|
||||
{
|
||||
return PathUtility::pathinfo($this->getName(), PATHINFO_FILENAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
* @return int<0, max>
|
||||
*/
|
||||
public function getSize(): int
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821480);
|
||||
}
|
||||
if (empty($this->properties['size'])) {
|
||||
$fileInfo = $this->getStorage()->getFileInfoByIdentifier($this->getIdentifier(), ['size']);
|
||||
$size = array_pop($fileInfo);
|
||||
} else {
|
||||
$size = $this->properties['size'];
|
||||
}
|
||||
return MathUtility::canBeInterpretedAsInteger($size) ? (int)$size : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uid of this file
|
||||
*/
|
||||
public function getUid(): int
|
||||
{
|
||||
return (int)$this->getProperty('uid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Sha1 of this file
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getSha1(): string
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821481);
|
||||
}
|
||||
return $this->getStorage()->hashFile($this, 'sha1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation time of the file as Unix timestamp
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getCreationTime(): int
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821487);
|
||||
}
|
||||
return (int)$this->getProperty('creation_date');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date (as UNIX timestamp) the file was last modified.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getModificationTime(): int
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821488);
|
||||
}
|
||||
return (int)$this->getProperty('modification_date');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extension of this file in a lower-case variant
|
||||
*/
|
||||
public function getExtension(): string
|
||||
{
|
||||
$pathinfo = PathUtility::pathinfo($this->getName());
|
||||
return strtolower($pathinfo['extension'] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIME type of this file
|
||||
*
|
||||
* @return non-empty-string mime type
|
||||
*/
|
||||
public function getMimeType(): string
|
||||
{
|
||||
if ($this->properties['mime_type'] ?? false) {
|
||||
return $this->properties['mime_type'];
|
||||
}
|
||||
$fileInfo = $this->getStorage()->getFileInfoByIdentifier($this->getIdentifier(), ['mimetype']);
|
||||
return array_pop($fileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fileType of this file
|
||||
* basically there are only five main "file types"
|
||||
* "audio"
|
||||
* "image"
|
||||
* "software"
|
||||
* "text"
|
||||
* "video"
|
||||
* "other"
|
||||
* see FileType enum
|
||||
*/
|
||||
public function getType(): int
|
||||
{
|
||||
return $this->getFileType()->value;
|
||||
}
|
||||
|
||||
public function isType(FileType $fileType): bool
|
||||
{
|
||||
return $this->getFileType() === $fileType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fileType of this file
|
||||
* basically there are only five main "file types"
|
||||
* "audio"
|
||||
* "image"
|
||||
* "software"
|
||||
* "text"
|
||||
* "video"
|
||||
* "other"
|
||||
* see FileType enum
|
||||
*/
|
||||
public function getFileType(): FileType
|
||||
{
|
||||
// this basically extracts the mimetype and guess the filetype based
|
||||
// on the first part of the mimetype works for 99% of all cases, and
|
||||
// we don't need to make an SQL statement like EXT:media does currently
|
||||
if (!($this->properties['type'] ?? false)) {
|
||||
$this->properties['type'] = FileType::tryFromMimeType($this->getMimeType())->value;
|
||||
}
|
||||
return $this->properties['type'] instanceof FileType ? $this->properties['type'] : FileType::from((int)$this->properties['type']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful to find out if this file can be previewed or resized as image.
|
||||
* @return bool true if File has an image-extension according to $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
|
||||
*/
|
||||
public function isImage(): bool
|
||||
{
|
||||
return GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] ?? ''), $this->getExtension()) && $this->getSize() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful to find out if this file has a file extension based on any of the registered media extensions
|
||||
* @return bool true if File is a media-extension according to $GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext']
|
||||
*/
|
||||
public function isMediaFile(): bool
|
||||
{
|
||||
return GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['SYS']['mediafile_ext'] ?? ''), $this->getExtension()) && $this->getSize() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Useful to find out if this file can be edited.
|
||||
*
|
||||
* @return bool true if File is a text-based file extension according to $GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext']
|
||||
*/
|
||||
public function isTextFile(): bool
|
||||
{
|
||||
return GeneralUtility::inList(strtolower($GLOBALS['TYPO3_CONF_VARS']['SYS']['textfile_ext'] ?? ''), $this->getExtension());
|
||||
}
|
||||
/******************
|
||||
* CONTENTS RELATED
|
||||
******************/
|
||||
/**
|
||||
* Get the contents of this file
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getContents(): string
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821479);
|
||||
}
|
||||
return $this->getStorage()->getFileContents($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the current file contents with the given string
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @return $this
|
||||
*/
|
||||
public function setContents(string $contents): self
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821478);
|
||||
}
|
||||
$this->getStorage()->setFileContents($this, $contents);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* STORAGE AND MANAGEMENT RELATED METHODS
|
||||
****************************************/
|
||||
|
||||
/**
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function getStorage(): ResourceStorage
|
||||
{
|
||||
if ($this->storage === null) {
|
||||
throw new \RuntimeException('You\'re using fileObjects without a storage.', 1381570091);
|
||||
}
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this file exists. This should normally always return TRUE;
|
||||
* it might only return FALSE when this object has been created from an
|
||||
* index record without checking for.
|
||||
*
|
||||
* @return bool TRUE if this file physically exists
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
if ($this->deleted) {
|
||||
return false;
|
||||
}
|
||||
return $this->storage->hasFile($this->getIdentifier());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the storage this file is located in. This is only meant for
|
||||
* \TYPO3\CMS\Core\Resource-internal usage; don't use it to move files.
|
||||
*
|
||||
* @internal Should only be used by other parts of the File API (e.g. drivers after moving a file)
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setStorage(ResourceStorage $storage): self
|
||||
{
|
||||
$this->storage = $storage;
|
||||
$this->properties['storage'] = $storage->getUid();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a combined identifier of this file, i.e. the storage UID and the
|
||||
* folder identifier separated by a colon ":".
|
||||
*
|
||||
* @return string Combined storage and file identifier, e.g. StorageUID:path/and/fileName.png
|
||||
*/
|
||||
public function getCombinedIdentifier(): string
|
||||
{
|
||||
if (!empty($this->properties['storage']) && MathUtility::canBeInterpretedAsInteger($this->properties['storage'])) {
|
||||
$combinedIdentifier = $this->properties['storage'] . ':' . $this->getIdentifier();
|
||||
} else {
|
||||
$combinedIdentifier = $this->getStorage()->getUid() . ':' . $this->getIdentifier();
|
||||
}
|
||||
return $combinedIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes this file from its storage. This also means that this object becomes useless.
|
||||
*/
|
||||
public function delete(): bool
|
||||
{
|
||||
// The storage will mark this file as deleted
|
||||
$wasDeleted = $this->getStorage()->deleteFile($this);
|
||||
|
||||
// Unset all properties when deleting the file, as they will be stale anyway
|
||||
// This needs to happen AFTER the storage deleted the file, because the storage
|
||||
// emits a signal, which passes the file object to the slots, which may need
|
||||
// all file properties of the deleted file.
|
||||
$this->properties = [];
|
||||
|
||||
return $wasDeleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks this file as deleted. This should only be used inside the
|
||||
* File Abstraction Layer, as it is a low-level API method.
|
||||
*/
|
||||
public function setDeleted(): void
|
||||
{
|
||||
$this->deleted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if this file has been deleted
|
||||
*/
|
||||
public function isDeleted(): bool
|
||||
{
|
||||
return $this->deleted;
|
||||
}
|
||||
|
||||
/*****************
|
||||
* SPECIAL METHODS
|
||||
*****************/
|
||||
/**
|
||||
* Returns a publicly accessible URL for this file
|
||||
*
|
||||
* WARNING: Access to the file may be restricted by further means, e.g. some
|
||||
* web-based authentication. You have to take care of this yourself.
|
||||
*
|
||||
* @return string|null NULL if file is deleted, the generated URL otherwise
|
||||
*/
|
||||
public function getPublicUrl(): ?string
|
||||
{
|
||||
if ($this->deleted) {
|
||||
return null;
|
||||
}
|
||||
return $this->getStorage()->getPublicUrl($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a path to a local version of this file to process it locally (e.g. with some system tool).
|
||||
* If the file is normally located on a remote storages, this creates a local copy.
|
||||
* If the file is already on the local system, this only makes a new copy if $writable is set to TRUE.
|
||||
*
|
||||
* @param bool $writable Set this to FALSE if you only want to do read operations on the file.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getForLocalProcessing(bool $writable = true): string
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821486);
|
||||
}
|
||||
return $this->getStorage()->getFileForLocalProcessing($this, $writable);
|
||||
}
|
||||
|
||||
/***********************
|
||||
* INDEX RELATED METHODS
|
||||
***********************/
|
||||
/**
|
||||
* Updates properties of this object.
|
||||
* This method is used to reconstitute settings from the
|
||||
* database into this object after being instantiated.
|
||||
*/
|
||||
abstract public function updateProperties(array $properties);
|
||||
|
||||
public function getParentFolder(): Folder
|
||||
{
|
||||
return $this->getStorage()->getFolder($this->getStorage()->getFolderIdentifierFromFileIdentifier($this->getIdentifier()));
|
||||
}
|
||||
}
|
||||
@@ -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\Resource\Cache;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use TYPO3\CMS\Core\Attribute\AsEventListener;
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterFileContentsSetEvent;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterFileDeletedEvent;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterFileMovedEvent;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterFileRenamedEvent;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterFileReplacedEvent;
|
||||
|
||||
final readonly class FlushCacheTagForFile
|
||||
{
|
||||
public function __construct(
|
||||
private CacheManager $cacheManager,
|
||||
#[Autowire(expression: 'service("features").isFeatureEnabled("frontend.cache.autoTagging")')]
|
||||
private bool $autoTagging
|
||||
) {}
|
||||
|
||||
#[AsEventListener(event: AfterFileContentsSetEvent::class)]
|
||||
#[AsEventListener(event: AfterFileDeletedEvent::class)]
|
||||
#[AsEventListener(event: AfterFileMovedEvent::class)]
|
||||
#[AsEventListener(event: AfterFileRenamedEvent::class)]
|
||||
#[AsEventListener(event: AfterFileReplacedEvent::class)]
|
||||
public function __invoke(
|
||||
AfterFileContentsSetEvent|AfterFileDeletedEvent|AfterFileMovedEvent|AfterFileRenamedEvent|AfterFileReplacedEvent $event
|
||||
): void {
|
||||
if (!$this->autoTagging) {
|
||||
return;
|
||||
}
|
||||
$this->cacheManager->flushCachesByTag(sprintf('sys_file_%s', $event->getFile()->getProperty('uid')));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?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\Resource\Cache;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use TYPO3\CMS\Core\Attribute\AsEventListener;
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterFolderRenamedEvent;
|
||||
use TYPO3\CMS\Core\Resource\Event\BeforeFolderMovedEvent;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
final readonly class FlushCacheTagForFolder
|
||||
{
|
||||
public function __construct(
|
||||
private CacheManager $cacheManager,
|
||||
#[Autowire(expression: 'service("features").isFeatureEnabled("frontend.cache.autoTagging")')]
|
||||
private bool $autoTagging
|
||||
) {}
|
||||
|
||||
#[AsEventListener(event: AfterFolderRenamedEvent::class)]
|
||||
#[AsEventListener(event: BeforeFolderMovedEvent::class)]
|
||||
public function __invoke(AfterFolderRenamedEvent|BeforeFolderMovedEvent $event): void
|
||||
{
|
||||
if (!$this->autoTagging) {
|
||||
return;
|
||||
}
|
||||
$files = $event->getFolder()->getFiles(0, 0, Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, true);
|
||||
$this->cacheManager->flushCachesByTags(
|
||||
array_map(
|
||||
static fn(File $file) => sprintf('sys_file_%s', $file->getProperty('uid')),
|
||||
$files
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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\Resource\Cache;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autowire;
|
||||
use TYPO3\CMS\Core\Attribute\AsEventListener;
|
||||
use TYPO3\CMS\Core\Cache\CacheManager;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterFileMetaDataCreatedEvent;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterFileMetaDataDeletedEvent;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterFileMetaDataUpdatedEvent;
|
||||
|
||||
final readonly class FlushCacheTagForMetaData
|
||||
{
|
||||
public function __construct(
|
||||
private CacheManager $cacheManager,
|
||||
#[Autowire(expression: 'service("features").isFeatureEnabled("frontend.cache.autoTagging")')]
|
||||
private bool $autoTagging
|
||||
) {}
|
||||
|
||||
#[AsEventListener(event: AfterFileMetaDataCreatedEvent::class)]
|
||||
#[AsEventListener(event: AfterFileMetaDataDeletedEvent::class)]
|
||||
#[AsEventListener(event: AfterFileMetaDataUpdatedEvent::class)]
|
||||
public function __invoke(
|
||||
AfterFileMetaDataCreatedEvent|AfterFileMetaDataDeletedEvent|AfterFileMetaDataUpdatedEvent $event
|
||||
): void {
|
||||
if (!$this->autoTagging) {
|
||||
return;
|
||||
}
|
||||
$cacheTags = [sprintf('sys_file_%s', $event->getFileUid())];
|
||||
if (method_exists($event, 'getMetaDataUid')) {
|
||||
$cacheTags[] = sprintf('sys_file_metadata_%s', $event->getMetaDataUid());
|
||||
}
|
||||
$this->cacheManager->flushCachesByTags($cacheTags);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?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\Resource;
|
||||
|
||||
use TYPO3\CMS\Core\Type\BitSet;
|
||||
|
||||
class Capabilities extends BitSet
|
||||
{
|
||||
/**
|
||||
* Capability for being browsable by (backend) users
|
||||
*/
|
||||
public const CAPABILITY_BROWSABLE = 1;
|
||||
/**
|
||||
* Capability for publicly accessible storages (= accessible from the web)
|
||||
*/
|
||||
public const CAPABILITY_PUBLIC = 2;
|
||||
/**
|
||||
* Capability for writable storages. This only signifies writability in
|
||||
* general - this might also be further limited by configuration.
|
||||
*/
|
||||
public const CAPABILITY_WRITABLE = 4;
|
||||
/**
|
||||
* Whether identifiers contain hierarchy information (folder structure).
|
||||
*/
|
||||
public const CAPABILITY_HIERARCHICAL_IDENTIFIERS = 8;
|
||||
|
||||
/**
|
||||
* @param self::CAPABILITY_* $capability
|
||||
* @return $this
|
||||
*/
|
||||
public function removeCapability(int $capability): self
|
||||
{
|
||||
$this->unset($capability);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param self::CAPABILITY_* ...$capabilities
|
||||
* @return $this
|
||||
*/
|
||||
public function addCapabilities(int ...$capabilities): self
|
||||
{
|
||||
foreach ($capabilities as $capability) {
|
||||
$this->set($capability);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param self::CAPABILITY_* $capability
|
||||
*/
|
||||
public function hasCapability(int $capability): bool
|
||||
{
|
||||
return $this->get($capability);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Collection;
|
||||
|
||||
use TYPO3\CMS\Core\Collection\AbstractRecordCollection;
|
||||
use TYPO3\CMS\Core\Collection\CollectionInterface;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
|
||||
/**
|
||||
* Abstract collection.
|
||||
* @extends AbstractRecordCollection<FileInterface>
|
||||
*/
|
||||
abstract class AbstractFileCollection extends AbstractRecordCollection
|
||||
{
|
||||
/**
|
||||
* The table name collections are stored to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $storageTableName = 'sys_file_collection';
|
||||
|
||||
/**
|
||||
* The type of file collection
|
||||
* (see \TYPO3\CMS\Core\Collection\RecordCollectionRepository::TYPE constants)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $type;
|
||||
|
||||
/**
|
||||
* The name of the field items are handled with
|
||||
* (usually either criteria, items or folder)
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $itemsCriteriaField;
|
||||
|
||||
/**
|
||||
* Field contents of $itemsCriteriaField. Defines which the items or search criteria for the items
|
||||
* depending on the type (see self::$type above) of this file collection.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $itemsCriteria;
|
||||
|
||||
/**
|
||||
* Name of the table records of this collection are stored in
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $itemTableName = 'sys_file';
|
||||
|
||||
/**
|
||||
* Sets the description.
|
||||
*
|
||||
* @param string $description
|
||||
*/
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the key of the current element
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function key(): mixed
|
||||
{
|
||||
/** @var File $currentRecord */
|
||||
$currentRecord = $this->storage->current();
|
||||
return $currentRecord->getIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates comma-separated list of entry uids for usage in DataHandler
|
||||
*
|
||||
* @param bool $includeTableName
|
||||
* @return string
|
||||
*/
|
||||
protected function getItemUidList($includeTableName = false)
|
||||
{
|
||||
$list = [];
|
||||
/** @var File $entry */
|
||||
foreach ($this->storage as $entry) {
|
||||
$list[] = $this->getItemTableName() . '_' . $entry->getUid();
|
||||
}
|
||||
return implode(',', $list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the persistable properties and contents
|
||||
* which are processable by DataHandler.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getPersistableDataArray()
|
||||
{
|
||||
return [
|
||||
'title' => $this->getTitle(),
|
||||
'type' => static::$type,
|
||||
'description' => $this->getDescription(),
|
||||
static::$itemsCriteriaField => $this->getItemsCriteria(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to method in \TYPO3\CMS\Core\Collection\AbstractRecordCollection,
|
||||
* but without 'table_name' => $this->getItemTableName()
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$itemArray = [];
|
||||
/** @var File $item */
|
||||
foreach ($this->storage as $item) {
|
||||
$itemArray[] = $item->toArray();
|
||||
}
|
||||
return [
|
||||
'uid' => $this->getIdentifier(),
|
||||
'title' => $this->getTitle(),
|
||||
'description' => $this->getDescription(),
|
||||
'items' => $itemArray,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current available items.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getItems()
|
||||
{
|
||||
$itemArray = [];
|
||||
/** @var FileInterface $item */
|
||||
foreach ($this->storage as $item) {
|
||||
$itemArray[] = $item;
|
||||
}
|
||||
return $itemArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to method in \TYPO3\CMS\Core\Collection\AbstractRecordCollection,
|
||||
* but without $this->itemTableName= $array['table_name'],
|
||||
* but with $this->storageItemsFieldContent = $array[self::$storageItemsField];
|
||||
*/
|
||||
public function fromArray(array $array)
|
||||
{
|
||||
$this->uid = $array['uid'];
|
||||
$this->title = $array['title'];
|
||||
$this->description = $array['description'];
|
||||
$this->itemsCriteria = $array[static::$itemsCriteriaField];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ths items criteria.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getItemsCriteria()
|
||||
{
|
||||
return $this->itemsCriteria;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the items criteria.
|
||||
*
|
||||
* @param mixed $itemsCriteria
|
||||
*/
|
||||
public function setItemsCriteria($itemsCriteria)
|
||||
{
|
||||
$this->itemsCriteria = $itemsCriteria;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a file to this collection.
|
||||
*/
|
||||
public function add(FileInterface $data)
|
||||
{
|
||||
$this->storage->push($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all files of another collection to the current one.
|
||||
*/
|
||||
public function addAll(CollectionInterface $other)
|
||||
{
|
||||
/** @var File $value */
|
||||
foreach ($other as $value) {
|
||||
$this->add($value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a file from this collection.
|
||||
*/
|
||||
public function remove(File $file)
|
||||
{
|
||||
$offset = 0;
|
||||
/** @var File $value */
|
||||
foreach ($this->storage as $value) {
|
||||
if ($value === $file) {
|
||||
break;
|
||||
}
|
||||
$offset++;
|
||||
}
|
||||
$this->storage->offsetUnset($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all elements of the current collection.
|
||||
*/
|
||||
public function removeAll()
|
||||
{
|
||||
$this->storage = new \SplDoublyLinkedList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Collection;
|
||||
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* A collection containing a set files belonging to certain categories.
|
||||
* This collection is persisted to the database with the accordant category identifiers.
|
||||
*/
|
||||
class CategoryBasedFileCollection extends AbstractFileCollection
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $storageTableName = 'sys_file_collection';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $type = 'categories';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $itemsCriteriaField = 'category';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $itemTableName = 'sys_category';
|
||||
|
||||
/**
|
||||
* Populates the content-entries of the collection
|
||||
*/
|
||||
public function loadContents()
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_category');
|
||||
$queryBuilder->getRestrictions()->removeAll();
|
||||
$statement = $queryBuilder->select('sys_file_metadata.file')
|
||||
->from('sys_category')
|
||||
->join(
|
||||
'sys_category',
|
||||
'sys_category_record_mm',
|
||||
'sys_category_record_mm',
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_category_record_mm.uid_local',
|
||||
$queryBuilder->quoteIdentifier('sys_category.uid')
|
||||
)
|
||||
)
|
||||
->join(
|
||||
'sys_category_record_mm',
|
||||
'sys_file_metadata',
|
||||
'sys_file_metadata',
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_category_record_mm.uid_foreign',
|
||||
$queryBuilder->quoteIdentifier('sys_file_metadata.uid')
|
||||
)
|
||||
)
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_category.uid',
|
||||
$queryBuilder->createNamedParameter($this->getItemsCriteria(), Connection::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
'sys_category_record_mm.tablenames',
|
||||
$queryBuilder->createNamedParameter('sys_file_metadata')
|
||||
)
|
||||
)
|
||||
->executeQuery();
|
||||
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||
while ($record = $statement->fetchAssociative()) {
|
||||
$this->add($resourceFactory->getFileObject((int)$record['file']));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Collection;
|
||||
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
|
||||
/**
|
||||
* Registry for FileCollection classes
|
||||
*/
|
||||
class FileCollectionRegistry implements SingletonInterface
|
||||
{
|
||||
/**
|
||||
* Registered FileCollection types
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $types = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
foreach ($GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['registeredCollections'] as $type => $class) {
|
||||
$this->registerFileCollectionClass($class, $type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a (new) FileCollection type
|
||||
*
|
||||
* @param string $className
|
||||
* @param string $type FileCollection type max length 30 chars (db field restriction)
|
||||
* @param bool $override existing FileCollection type
|
||||
* @return bool TRUE if registration succeeded
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function registerFileCollectionClass($className, $type, $override = false)
|
||||
{
|
||||
if (strlen($type) > 30) {
|
||||
throw new \InvalidArgumentException('FileCollection type can have a max string length of 30 bytes', 1391295611);
|
||||
}
|
||||
|
||||
if (!class_exists($className)) {
|
||||
throw new \InvalidArgumentException('Class ' . $className . ' does not exist.', 1391295613);
|
||||
}
|
||||
|
||||
if (!in_array(AbstractFileCollection::class, class_parents($className) ?: [], true)) {
|
||||
throw new \InvalidArgumentException('FileCollection ' . $className . ' needs to extend the AbstractFileCollection.', 1391295633);
|
||||
}
|
||||
|
||||
if (isset($this->types[$type])) {
|
||||
// Return immediately without changing configuration
|
||||
if ($this->types[$type] === $className) {
|
||||
return true;
|
||||
}
|
||||
if (!$override) {
|
||||
throw new \InvalidArgumentException('FileCollections ' . $type . ' is already registered.', 1391295643);
|
||||
}
|
||||
}
|
||||
|
||||
$this->types[$type] = $className;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a class name for a given type
|
||||
*
|
||||
* @param string $type
|
||||
* @return string The class name
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getFileCollectionClass($type)
|
||||
{
|
||||
if (!isset($this->types[$type])) {
|
||||
throw new \InvalidArgumentException('Desired FileCollection type "' . $type . '" is not in the list of available FileCollections.', 1391295644);
|
||||
}
|
||||
return $this->types[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given FileCollection type exists
|
||||
*
|
||||
* @param string $type Type of the FileCollection
|
||||
* @return bool TRUE if the FileCollection exists, FALSE otherwise
|
||||
*/
|
||||
public function fileCollectionTypeExists($type)
|
||||
{
|
||||
return isset($this->types[$type]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Collection;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\StorageRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* A collection containing a set of files to be represented as a (virtual) folder.
|
||||
* This collection is persisted to the database with the accordant folder reference.
|
||||
*/
|
||||
class FolderBasedFileCollection extends AbstractFileCollection
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $storageTableName = 'sys_file_collection';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $type = 'folder';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $itemsCriteriaField = 'folder';
|
||||
|
||||
/**
|
||||
* The folder
|
||||
*/
|
||||
protected ?Folder $folder = null;
|
||||
protected bool $recursive = false;
|
||||
|
||||
/**
|
||||
* Populates the content-entries of the storage
|
||||
*
|
||||
* Queries the underlying storage for entries of the collection
|
||||
* and adds them to the collection data.
|
||||
*
|
||||
* If the content entries of the storage had not been loaded on creation
|
||||
* ($fillItems = false) this function is to be used for loading the contents
|
||||
* afterward.
|
||||
*/
|
||||
public function loadContents()
|
||||
{
|
||||
if ($this->folder instanceof Folder) {
|
||||
$entries = $this->folder->getFiles(0, 0, Folder::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, $this->recursive);
|
||||
foreach ($entries as $entry) {
|
||||
$this->add($entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the items criteria.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getItemsCriteria()
|
||||
{
|
||||
return $this->folder->getCombinedIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of the persistable properties and contents
|
||||
* which are processable by DataHandler.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getPersistableDataArray()
|
||||
{
|
||||
return [
|
||||
'title' => $this->getTitle(),
|
||||
'type' => self::$type,
|
||||
'description' => $this->getDescription(),
|
||||
'folder_identifier' => $this->folder->getCombinedIdentifier(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to method in \TYPO3\CMS\Core\Collection\AbstractRecordCollection,
|
||||
* but without $this->itemTableName= $array['table_name'],
|
||||
* but with $this->storageItemsFieldContent = $array[self::$storageItemsField];
|
||||
*/
|
||||
public function fromArray(array $array)
|
||||
{
|
||||
$this->uid = (int)$array['uid'];
|
||||
$this->title = (string)$array['title'];
|
||||
$this->description = (string)$array['description'];
|
||||
$this->recursive = (bool)$array['recursive'];
|
||||
if (str_contains($array['folder_identifier'] ?? '', ':')) {
|
||||
$parts = GeneralUtility::trimExplode(':', $array['folder_identifier']);
|
||||
$storageRepository = GeneralUtility::makeInstance(StorageRepository::class);
|
||||
$storage = $storageRepository->findByUid((int)$parts[0]);
|
||||
if ($storage) {
|
||||
$this->folder = $storage->getFolder($parts[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?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\Resource\Collection;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileReference;
|
||||
|
||||
/**
|
||||
* When first accessed, this class will initialize itself and find the file references
|
||||
* for this record field.
|
||||
*
|
||||
* This class acts as a "Value holder", as it only fetches the related file references
|
||||
* when needed.
|
||||
*
|
||||
* @internal not part of public API, as this needs to be streamlined and proven
|
||||
*/
|
||||
class LazyFileReferenceCollection implements \IteratorAggregate, \ArrayAccess, \Countable
|
||||
{
|
||||
/**
|
||||
* @var FileReference[]|\Closure
|
||||
*/
|
||||
private array|\Closure $items;
|
||||
|
||||
public function __construct(
|
||||
private readonly mixed $fieldValue,
|
||||
\Closure $initialization
|
||||
) {
|
||||
$this->items = $initialization;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
$this->initialize();
|
||||
return count($this->items);
|
||||
}
|
||||
|
||||
private function initialize(): void
|
||||
{
|
||||
if ($this->items instanceof \Closure) {
|
||||
$this->items = ($this->items)();
|
||||
}
|
||||
}
|
||||
|
||||
public function getIterator(): \Iterator
|
||||
{
|
||||
$this->initialize();
|
||||
return new \ArrayIterator($this->items);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->fieldValue;
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
$this->initialize();
|
||||
return isset($this->items[$offset]);
|
||||
}
|
||||
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->items[$offset] ?? null;
|
||||
}
|
||||
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
if ($value instanceof FileReference === false) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Modifying the file reference collection is only allowed by setting a value of type FileReference.',
|
||||
1723188317
|
||||
);
|
||||
}
|
||||
$this->items[$offset] = $value;
|
||||
}
|
||||
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
throw new \RuntimeException('Removing items from the file reference collection is not implemented.', 1723188318);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?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\Resource\Collection;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* When first accessed, this class will initialize itself and find the folders
|
||||
* for this record field.
|
||||
*
|
||||
* This class acts as a "Value holder", as it only fetches the related folders
|
||||
* when needed.
|
||||
*
|
||||
* @internal not part of public API, as this needs to be streamlined and proven
|
||||
*/
|
||||
class LazyFolderCollection implements \IteratorAggregate, \ArrayAccess, \Countable
|
||||
{
|
||||
/**
|
||||
* @var Folder[]|\Closure
|
||||
*/
|
||||
private array|\Closure $items;
|
||||
|
||||
public function __construct(
|
||||
private readonly mixed $fieldValue,
|
||||
\Closure $initialization
|
||||
) {
|
||||
$this->items = $initialization;
|
||||
}
|
||||
|
||||
public function count(): int
|
||||
{
|
||||
$this->initialize();
|
||||
return count($this->items);
|
||||
}
|
||||
|
||||
private function initialize(): void
|
||||
{
|
||||
if ($this->items instanceof \Closure) {
|
||||
$this->items = ($this->items)();
|
||||
}
|
||||
}
|
||||
|
||||
public function getIterator(): \Iterator
|
||||
{
|
||||
$this->initialize();
|
||||
return new \ArrayIterator($this->items);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->fieldValue;
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
$this->initialize();
|
||||
return isset($this->items[$offset]);
|
||||
}
|
||||
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
$this->initialize();
|
||||
return $this->items[$offset] ?? null;
|
||||
}
|
||||
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
if ($value instanceof Folder === false) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Modifying the folder collection is only allowed by setting a value of type Folder.',
|
||||
1724136133
|
||||
);
|
||||
}
|
||||
$this->items[$offset] = $value;
|
||||
}
|
||||
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
throw new \RuntimeException('Removing items from the folder collection is not implemented.', 1724136134);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Collection;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileRepository;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* A collection containing a static set of files. This collection is persisted
|
||||
* to the database with references to all files it contains.
|
||||
*/
|
||||
class StaticFileCollection extends AbstractFileCollection
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $type = 'static';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $itemsCriteriaField = 'files';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $itemTableName = 'sys_file_reference';
|
||||
|
||||
/**
|
||||
* Populates the content-entries of the storage
|
||||
*
|
||||
* Queries the underlying storage for entries of the collection
|
||||
* and adds them to the collection data.
|
||||
*
|
||||
* If the content entries of the storage had not been loaded on creation
|
||||
* ($fillItems = false) this function is to be used for loading the contents
|
||||
* afterwards.
|
||||
*/
|
||||
public function loadContents()
|
||||
{
|
||||
$fileRepository = GeneralUtility::makeInstance(FileRepository::class);
|
||||
$fileReferences = $fileRepository->findByRelation('sys_file_collection', 'files', $this->getIdentifier());
|
||||
foreach ($fileReferences as $file) {
|
||||
$this->add($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?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\Resource;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\EventDispatcher\EventDispatcher;
|
||||
use TYPO3\CMS\Core\Resource\Event\AfterDefaultUploadFolderWasResolvedEvent;
|
||||
use TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException;
|
||||
|
||||
/**
|
||||
* Finds the best matching upload folder for a specific backend user
|
||||
* when uploading or selecting files, based on UserTSconfig or PageTSconfig
|
||||
*/
|
||||
#[Autoconfigure(public: true)]
|
||||
readonly class DefaultUploadFolderResolver
|
||||
{
|
||||
public function __construct(
|
||||
protected ResourceFactory $resourceFactory,
|
||||
protected EventDispatcher $eventDispatcher,
|
||||
) {}
|
||||
|
||||
public function resolve(BackendUserAuthentication $user, ?int $pid = null, ?string $table = null, ?string $field = null): Folder|bool
|
||||
{
|
||||
$uploadFolder = $this->getDefaultUploadFolderForUser($user);
|
||||
$uploadFolder = $this->getDefaultUploadFolderForPage($pid) ?? $uploadFolder;
|
||||
|
||||
$uploadFolder = $this->eventDispatcher->dispatch(
|
||||
new AfterDefaultUploadFolderWasResolvedEvent($uploadFolder, $pid, $table, $field)
|
||||
)->getUploadFolder() ?? $uploadFolder;
|
||||
|
||||
$uploadFolder = $uploadFolder ?? $this->getDefaultUploadFolder($user);
|
||||
|
||||
return $uploadFolder instanceof Folder ? $uploadFolder : false;
|
||||
}
|
||||
|
||||
public function getDefaultUploadFolderForUser(BackendUserAuthentication $backendUser): ?Folder
|
||||
{
|
||||
$uploadFolder = $backendUser->getTSConfig()['options.']['defaultUploadFolder'] ?? '';
|
||||
|
||||
return $this->resolveFolder($uploadFolder);
|
||||
}
|
||||
|
||||
public function getDefaultUploadFolderForPage(?int $pid): ?Folder
|
||||
{
|
||||
$uploadFolder = BackendUtility::getPagesTSconfig($pid)['options.']['defaultUploadFolder'] ?? '';
|
||||
|
||||
return $this->resolveFolder($uploadFolder);
|
||||
}
|
||||
|
||||
protected function resolveFolder(string $uploadPath): ?Folder
|
||||
{
|
||||
$uploadFolder = null;
|
||||
|
||||
if ($uploadPath) {
|
||||
try {
|
||||
$uploadFolder = $this->resourceFactory->getFolderObjectFromCombinedIdentifier($uploadPath);
|
||||
} catch (FolderDoesNotExistException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
return $uploadFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the first default folder of the first storage that the backend user has access to.
|
||||
* If the default storage is not available, all other storages are then checked as well.
|
||||
*
|
||||
* @param BackendUserAuthentication $backendUser
|
||||
* @return Folder|null
|
||||
*/
|
||||
protected function getDefaultUploadFolder(BackendUserAuthentication $backendUser): ?Folder
|
||||
{
|
||||
$uploadFolder = null;
|
||||
|
||||
foreach ($backendUser->getFileStorages() as $storage) {
|
||||
if ($storage->isDefault() && $storage->isWritable()) {
|
||||
try {
|
||||
$uploadFolder = $storage->getDefaultFolder();
|
||||
if ($uploadFolder->checkActionPermission('write')) {
|
||||
break;
|
||||
}
|
||||
$uploadFolder = null;
|
||||
} catch (Exception $folderAccessException) {
|
||||
// If the folder is not accessible (no permissions / does not exist) we skip this one.
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$uploadFolder instanceof Folder) {
|
||||
foreach ($backendUser->getFileStorages() as $storage) {
|
||||
if ($storage->isWritable()) {
|
||||
try {
|
||||
$uploadFolder = $storage->getDefaultFolder();
|
||||
if ($uploadFolder->checkActionPermission('write')) {
|
||||
break;
|
||||
}
|
||||
$uploadFolder = null;
|
||||
} catch (Exception $folderAccessException) {
|
||||
// If the folder is not accessible (no permissions / does not exist) try the next one.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $uploadFolder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?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\Resource\Driver;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Capabilities;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
/**
|
||||
* An abstract implementation of a storage driver.
|
||||
*/
|
||||
abstract class AbstractDriver implements DriverInterface
|
||||
{
|
||||
/*******************
|
||||
* CAPABILITIES
|
||||
*******************/
|
||||
/**
|
||||
* The capabilities of this driver. This value should be set in the constructor of derived classes.
|
||||
*/
|
||||
protected Capabilities $capabilities;
|
||||
|
||||
/**
|
||||
* The storage uid the driver was instantiated for
|
||||
*/
|
||||
protected ?int $storageUid = null;
|
||||
|
||||
/**
|
||||
* A list of all supported hash algorithms, written all lower case and
|
||||
* without any dashes etc. (e.g. sha1 instead of SHA-1)
|
||||
* Be sure to set this in inherited classes!
|
||||
*
|
||||
* @phpstan-var list<string>
|
||||
*
|
||||
* @todo: Remove this from this class. Properties of abstract classes MUST NOT be api. If all drivers
|
||||
* need to implement this, consider creating a new method stub in the DriverInterface or consider
|
||||
* creating a new SupportedHashAlgorithmsAwareInterface that demands implementations to provide said
|
||||
* information. Inside this abstract class, this property is useless, however.
|
||||
*/
|
||||
protected array $supportedHashAlgorithms = [];
|
||||
|
||||
/**
|
||||
* The configuration of this driver
|
||||
*/
|
||||
protected array $configuration = [];
|
||||
|
||||
/**
|
||||
* Creates this object.
|
||||
*/
|
||||
public function __construct(array $configuration = [])
|
||||
{
|
||||
$this->configuration = $configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a fileName for validity. This could be overridden in concrete
|
||||
* drivers if they have different file naming rules.
|
||||
*/
|
||||
protected function isValidFilename(string $fileName): bool
|
||||
{
|
||||
if (str_contains($fileName, '/')) {
|
||||
return false;
|
||||
}
|
||||
if (!preg_match('/^[\\pL\\d[:blank:]._-]*$/u', $fileName)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the storage uid the driver belongs to
|
||||
*/
|
||||
public function setStorageUid(int $storageUid): void
|
||||
{
|
||||
$this->storageUid = $storageUid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the capabilities of this driver.
|
||||
*/
|
||||
public function getCapabilities(): Capabilities
|
||||
{
|
||||
return $this->capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if this driver has the given capability.
|
||||
*
|
||||
* @phpstan-param Capabilities::CAPABILITY_* $capability
|
||||
*/
|
||||
public function hasCapability(int $capability): bool
|
||||
{
|
||||
return $this->getCapabilities()->hasCapability($capability);
|
||||
}
|
||||
|
||||
/*******************
|
||||
* FILE FUNCTIONS
|
||||
*******************/
|
||||
|
||||
/**
|
||||
* Returns a temporary path for a given file, including the file extension.
|
||||
*
|
||||
* @phpstan-param non-empty-string $fileIdentifier
|
||||
* @phpstan-return non-empty-string
|
||||
*/
|
||||
protected function getTemporaryPathForFile(string $fileIdentifier): string
|
||||
{
|
||||
return GeneralUtility::tempnam('fal-tempfile-', '.' . PathUtility::pathinfo($fileIdentifier, PATHINFO_EXTENSION));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes a file identifier, taking the case sensitivity of the file system
|
||||
* into account. This helps mitigating problems with case-insensitive
|
||||
* databases.
|
||||
*
|
||||
* @phpstan-param non-empty-string $identifier
|
||||
* @phpstan-return non-empty-string
|
||||
*/
|
||||
public function hashIdentifier(string $identifier): string
|
||||
{
|
||||
$identifier = $this->canonicalizeAndCheckFileIdentifier($identifier);
|
||||
return sha1($identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if this driver uses case-sensitive identifiers. NOTE: This
|
||||
* is a configurable setting, but the setting does not change the way the
|
||||
* underlying file system treats the identifiers; the setting should
|
||||
* therefore always reflect the file system and not try to change its
|
||||
* behaviour
|
||||
*/
|
||||
public function isCaseSensitiveFileSystem(): bool
|
||||
{
|
||||
if (isset($this->configuration['caseSensitive'])) {
|
||||
return (bool)$this->configuration['caseSensitive'];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the path given as parameter is valid
|
||||
*
|
||||
* @phpstan-param non-empty-string $filePath The file path (most times filePath)
|
||||
* @phpstan-return non-empty-string
|
||||
*/
|
||||
abstract protected function canonicalizeAndCheckFilePath(string $filePath): string;
|
||||
|
||||
/**
|
||||
* Makes sure the identifier given as parameter is valid
|
||||
*
|
||||
* @phpstan-param non-empty-string $fileIdentifier The file Identifier
|
||||
* @phpstan-return non-empty-string
|
||||
*/
|
||||
abstract protected function canonicalizeAndCheckFileIdentifier(string $fileIdentifier): string;
|
||||
|
||||
/**
|
||||
* Makes sure the identifier given as parameter is valid
|
||||
*
|
||||
* @phpstan-param non-empty-string $folderIdentifier The folder identifier
|
||||
* @phpstan-return non-empty-string
|
||||
*/
|
||||
abstract protected function canonicalizeAndCheckFolderIdentifier(string $folderIdentifier): string;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?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\Resource\Driver;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception\InvalidPathException;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\Utility\PathUtility;
|
||||
|
||||
/**
|
||||
* Contains a few classes that might be useful for hierarchical drivers.
|
||||
*/
|
||||
abstract class AbstractHierarchicalFilesystemDriver extends AbstractDriver
|
||||
{
|
||||
/**
|
||||
* Wrapper for \TYPO3\CMS\Core\Utility\GeneralUtility::validPathStr()
|
||||
*
|
||||
* @return bool TRUE if no '/', '..' or '\' is in the $theFile
|
||||
*/
|
||||
protected function isPathValid(string $theFile): bool
|
||||
{
|
||||
return GeneralUtility::validPathStr($theFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the given path is valid.
|
||||
*
|
||||
* @phpstan-param non-empty-string $filePath The file path (including the file name!)
|
||||
* @phpstan-return non-empty-string
|
||||
*/
|
||||
protected function canonicalizeAndCheckFilePath(string $filePath): string
|
||||
{
|
||||
$filePath = PathUtility::getCanonicalPath($filePath);
|
||||
// $filePath must be valid
|
||||
if (!$this->isPathValid($filePath)) {
|
||||
throw new InvalidPathException('File ' . $filePath . ' is not valid (".." and "//" is not allowed in path).', 1320286857);
|
||||
}
|
||||
return $filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the Path given as parameter is valid.
|
||||
*
|
||||
* @param string $fileIdentifier The file path (including the file name!)
|
||||
*/
|
||||
protected function canonicalizeAndCheckFileIdentifier(string $fileIdentifier): string
|
||||
{
|
||||
if ($fileIdentifier !== '') {
|
||||
$fileIdentifier = $this->canonicalizeAndCheckFilePath($fileIdentifier);
|
||||
$fileIdentifier = '/' . ltrim($fileIdentifier, '/');
|
||||
if (!$this->isCaseSensitiveFileSystem()) {
|
||||
$fileIdentifier = mb_strtolower($fileIdentifier, 'utf-8');
|
||||
}
|
||||
}
|
||||
return $fileIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure the Path given as parameter is valid.
|
||||
*
|
||||
* @phpstan-param non-empty-string $folderIdentifier The file path (including the file name!)
|
||||
* @phpstan-return non-empty-string
|
||||
*/
|
||||
protected function canonicalizeAndCheckFolderIdentifier(string $folderIdentifier): string
|
||||
{
|
||||
if ($folderIdentifier === '/') {
|
||||
return '/';
|
||||
}
|
||||
return rtrim($this->canonicalizeAndCheckFileIdentifier($folderIdentifier), '/') . '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of the folder the file resides in.
|
||||
*
|
||||
* @phpstan-param non-empty-string $fileIdentifier
|
||||
* @phpstan-return non-empty-string
|
||||
*/
|
||||
public function getParentFolderIdentifierOfIdentifier(string $fileIdentifier): string
|
||||
{
|
||||
$fileIdentifier = $this->canonicalizeAndCheckFileIdentifier($fileIdentifier);
|
||||
return rtrim(GeneralUtility::fixWindowsFilePath(PathUtility::dirname($fileIdentifier)), '/') . '/';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,459 @@
|
||||
<?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\Resource\Driver;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Capabilities;
|
||||
|
||||
/**
|
||||
* An interface Drivers have to implement to fulfil the needs
|
||||
* of the FAL API.
|
||||
*/
|
||||
interface DriverInterface
|
||||
{
|
||||
/**
|
||||
* Processes the configuration for this driver.
|
||||
*/
|
||||
public function processConfiguration(): void;
|
||||
|
||||
/**
|
||||
* Sets the storage uid the driver belongs to
|
||||
*/
|
||||
public function setStorageUid(int $storageUid): void;
|
||||
|
||||
/**
|
||||
* Initializes this object. This is called by the storage after the driver
|
||||
* has been attached.
|
||||
*/
|
||||
public function initialize(): void;
|
||||
|
||||
/**
|
||||
* Returns the capabilities of this driver.
|
||||
*/
|
||||
public function getCapabilities(): Capabilities;
|
||||
|
||||
/**
|
||||
* Merges the capabilities merged by the user at the storage
|
||||
* configuration into the actual capabilities of the driver
|
||||
* and returns the result.
|
||||
*/
|
||||
public function mergeConfigurationCapabilities(Capabilities $capabilities): Capabilities;
|
||||
|
||||
/**
|
||||
* Returns TRUE if this driver has the given capability.
|
||||
*
|
||||
* @param Capabilities::CAPABILITY_* $capability
|
||||
*/
|
||||
public function hasCapability(int $capability): bool;
|
||||
|
||||
/**
|
||||
* Returns TRUE if this driver uses case-sensitive identifiers. NOTE: This
|
||||
* is a configurable setting, but the setting does not change the way the
|
||||
* underlying file system treats the identifiers; the setting should
|
||||
* therefore always reflect the file system and not try to change its
|
||||
* behaviour
|
||||
*/
|
||||
public function isCaseSensitiveFileSystem(): bool;
|
||||
|
||||
/**
|
||||
* Cleans a fileName from not allowed characters
|
||||
*
|
||||
* @param non-empty-string $fileName
|
||||
* @return non-empty-string the sanitized filename
|
||||
*/
|
||||
public function sanitizeFileName(string $fileName): string;
|
||||
|
||||
/**
|
||||
* Hashes a file identifier, taking the case sensitivity of the file system
|
||||
* into account. This helps mitigating problems with case-insensitive
|
||||
* databases.
|
||||
*
|
||||
* @param non-empty-string $identifier
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function hashIdentifier(string $identifier): string;
|
||||
|
||||
/**
|
||||
* Returns the identifier of the root level folder of the storage.
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getRootLevelFolder(): string;
|
||||
|
||||
/**
|
||||
* Returns the identifier of the default folder new files should be put into.
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getDefaultFolder(): string;
|
||||
|
||||
/**
|
||||
* Returns the identifier of the folder the file resides in
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getParentFolderIdentifierOfIdentifier(string $fileIdentifier): string;
|
||||
|
||||
/**
|
||||
* Returns the public URL to a file.
|
||||
* Either fully qualified URL or relative to public web path (rawurlencoded).
|
||||
*
|
||||
* @param non-empty-string $identifier
|
||||
* @return non-empty-string|null NULL if file is missing or deleted, the generated url otherwise
|
||||
*/
|
||||
public function getPublicUrl(string $identifier): ?string;
|
||||
|
||||
/**
|
||||
* Creates a folder, within a parent folder.
|
||||
* If no parent folder is given, a root level folder will be created
|
||||
*
|
||||
* @param non-empty-string $newFolderName
|
||||
* @return non-empty-string the Identifier of the new folder
|
||||
*/
|
||||
public function createFolder(string $newFolderName, string $parentFolderIdentifier = '', bool $recursive = false): string;
|
||||
|
||||
/**
|
||||
* Renames a folder in this storage.
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @param non-empty-string $newName
|
||||
* @return array<string, string> A map of old to new file identifiers of all affected resources
|
||||
*/
|
||||
public function renameFolder(string $folderIdentifier, string $newName): array;
|
||||
|
||||
/**
|
||||
* Removes a folder in filesystem.
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
*/
|
||||
public function deleteFolder(string $folderIdentifier, bool $deleteRecursively = false): bool;
|
||||
|
||||
/**
|
||||
* Checks if a file exists.
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
*/
|
||||
public function fileExists(string $fileIdentifier): bool;
|
||||
|
||||
/**
|
||||
* Checks if a folder exists.
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
*/
|
||||
public function folderExists(string $folderIdentifier): bool;
|
||||
|
||||
/**
|
||||
* Checks if a folder contains files and (if supported) other folders.
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @return bool TRUE if there are no files and folders within $folder
|
||||
*/
|
||||
public function isFolderEmpty(string $folderIdentifier): bool;
|
||||
|
||||
/**
|
||||
* Adds a file from the local server hard disk to a given path in TYPO3s
|
||||
* virtual file system. This assumes that the local file exists, so no
|
||||
* further check is done here! After a successful operation the original
|
||||
* file must not exist anymore.
|
||||
*
|
||||
* @param non-empty-string $localFilePath within public web path
|
||||
* @param non-empty-string $targetFolderIdentifier
|
||||
* @param string $newFileName optional, if not given original name is used
|
||||
* @param bool $removeOriginal if set the original file will be removed
|
||||
* after successful operation
|
||||
* @return non-empty-string the identifier of the new file
|
||||
*/
|
||||
public function addFile(string $localFilePath, string $targetFolderIdentifier, string $newFileName = '', bool $removeOriginal = true): string;
|
||||
|
||||
/**
|
||||
* Creates a new (empty) file and returns the identifier.
|
||||
*
|
||||
* @param non-empty-string $fileName
|
||||
* @param non-empty-string $parentFolderIdentifier
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function createFile(string $fileName, string $parentFolderIdentifier): string;
|
||||
|
||||
/**
|
||||
* Copies a file *within* the current storage.
|
||||
* Note that this is only about an inner storage copy action,
|
||||
* where a file is just copied to another folder in the same storage.
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
* @param non-empty-string $targetFolderIdentifier
|
||||
* @param non-empty-string $fileName
|
||||
* @return non-empty-string the Identifier of the new file
|
||||
*/
|
||||
public function copyFileWithinStorage(string $fileIdentifier, string $targetFolderIdentifier, string $fileName): string;
|
||||
|
||||
/**
|
||||
* Renames a file in this storage.
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
* @param non-empty-string $newName The target path (including the file name!)
|
||||
* @return non-empty-string The identifier of the file after renaming
|
||||
*/
|
||||
public function renameFile(string $fileIdentifier, string $newName): string;
|
||||
|
||||
/**
|
||||
* Replaces a file with file in local file system.
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
* @param non-empty-string $localFilePath
|
||||
*/
|
||||
public function replaceFile(string $fileIdentifier, string $localFilePath): bool;
|
||||
|
||||
/**
|
||||
* Removes a file from the filesystem. This does not check if the file is
|
||||
* still used or if it is a bad idea to delete it for some other reason
|
||||
* this has to be taken care of in the upper layers (e.g. the Storage)!
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
*/
|
||||
public function deleteFile(string $fileIdentifier): bool;
|
||||
|
||||
/**
|
||||
* Creates a hash for a file.
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
* @param non-empty-string $hashAlgorithm The hash algorithm to use
|
||||
*/
|
||||
public function hash(string $fileIdentifier, string $hashAlgorithm): string;
|
||||
|
||||
/**
|
||||
* Moves a file *within* the current storage.
|
||||
* Note that this is only about an inner-storage move action,
|
||||
* where a file is just moved to another folder in the same storage.
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
* @param non-empty-string $targetFolderIdentifier
|
||||
* @param non-empty-string $newFileName
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function moveFileWithinStorage(string $fileIdentifier, string $targetFolderIdentifier, string $newFileName): string;
|
||||
|
||||
/**
|
||||
* Folder equivalent to moveFileWithinStorage().
|
||||
*
|
||||
* @param non-empty-string $sourceFolderIdentifier
|
||||
* @param non-empty-string $targetFolderIdentifier
|
||||
* @param non-empty-string $newFolderName
|
||||
* @return array<non-empty-string, non-empty-string> All files which are affected, map of old => new file identifiers
|
||||
*/
|
||||
public function moveFolderWithinStorage(string $sourceFolderIdentifier, string $targetFolderIdentifier, string $newFolderName): array;
|
||||
|
||||
/**
|
||||
* Folder equivalent to copyFileWithinStorage().
|
||||
*
|
||||
* @param non-empty-string $sourceFolderIdentifier
|
||||
* @param non-empty-string $targetFolderIdentifier
|
||||
* @param non-empty-string $newFolderName
|
||||
*/
|
||||
public function copyFolderWithinStorage(string $sourceFolderIdentifier, string $targetFolderIdentifier, string $newFolderName): bool;
|
||||
|
||||
/**
|
||||
* Returns the contents of a file. Beware that this requires to load the
|
||||
* complete file into memory and also may require fetching the file from an
|
||||
* external location. So this might be an expensive operation (both in terms
|
||||
* of processing resources and money) for large files.
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
*/
|
||||
public function getFileContents(string $fileIdentifier): string;
|
||||
|
||||
/**
|
||||
* Sets the contents of a file to the specified value.
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
* @return int<0, max> The number of bytes written to the file
|
||||
*/
|
||||
public function setFileContents(string $fileIdentifier, string $contents): int;
|
||||
|
||||
/**
|
||||
* Checks if a file inside a folder exists
|
||||
*
|
||||
* @param non-empty-string $fileName
|
||||
* @param non-empty-string $folderIdentifier
|
||||
*/
|
||||
public function fileExistsInFolder(string $fileName, string $folderIdentifier): bool;
|
||||
|
||||
/**
|
||||
* Checks if a folder inside a folder exists.
|
||||
*
|
||||
* @param non-empty-string $folderName
|
||||
* @param non-empty-string $folderIdentifier
|
||||
*/
|
||||
public function folderExistsInFolder(string $folderName, string $folderIdentifier): bool;
|
||||
|
||||
/**
|
||||
* Returns a path to a local copy of a file for processing it. When changing the
|
||||
* file, you have to take care of replacing the current version yourself!
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
* @param bool $writable Set this to FALSE if you only need the file for read
|
||||
* operations. This might speed up things, e.g. by using
|
||||
* a cached local version. Never modify the file if you
|
||||
* have set this flag!
|
||||
* @return non-empty-string The path to the file on the local disk
|
||||
*/
|
||||
public function getFileForLocalProcessing(string $fileIdentifier, bool $writable = true): string;
|
||||
|
||||
/**
|
||||
* Returns the permissions of a file/folder as an array
|
||||
* (keys r, w) of boolean flags
|
||||
*
|
||||
* @param non-empty-string $identifier
|
||||
* @return array{r: bool, w: bool}
|
||||
*/
|
||||
public function getPermissions(string $identifier): array;
|
||||
|
||||
/**
|
||||
* Directly output the contents of the file to the output
|
||||
* buffer. Should not take care of header files or flushing
|
||||
* buffer before. Will be taken care of by the Storage.
|
||||
*
|
||||
* @param non-empty-string $identifier
|
||||
*/
|
||||
public function dumpFileContents(string $identifier): void;
|
||||
|
||||
/**
|
||||
* Checks if a given identifier is within a container, e.g. if
|
||||
* a file or folder is within another folder.
|
||||
* This can e.g. be used to check for web-mounts.
|
||||
*
|
||||
* Hint: this also needs to return TRUE if the given identifier
|
||||
* matches the container identifier to allow access to the root
|
||||
* folder of a file mount.
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @param non-empty-string $identifier identifier to be checked against $folderIdentifier
|
||||
* @return bool TRUE if $content is within or matches $folderIdentifier
|
||||
*/
|
||||
public function isWithin(string $folderIdentifier, string $identifier): bool;
|
||||
|
||||
/**
|
||||
* Returns information about a file.
|
||||
*
|
||||
* @param non-empty-string $fileIdentifier
|
||||
* @param list<string> $propertiesToExtract Array of properties which are be extracted
|
||||
* If empty all will be extracted
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function getFileInfoByIdentifier(string $fileIdentifier, array $propertiesToExtract = []): array;
|
||||
|
||||
/**
|
||||
* Returns information about a folder.
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @return array{
|
||||
* identifier: non-empty-string,
|
||||
* name: string,
|
||||
* mtime: int,
|
||||
* ctime: int,
|
||||
* storage: int,
|
||||
* }
|
||||
*/
|
||||
public function getFolderInfoByIdentifier(string $folderIdentifier): array;
|
||||
|
||||
/**
|
||||
* Returns the identifier of a file inside the folder
|
||||
*
|
||||
* @param non-empty-string $fileName
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @return non-empty-string file identifier
|
||||
*/
|
||||
public function getFileInFolder(string $fileName, string $folderIdentifier): string;
|
||||
|
||||
/**
|
||||
* Returns a list of files inside the specified path
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @param int<0, max> $start
|
||||
* @param int<0, max> $numberOfItems
|
||||
* @param list<callable> $filenameFilterCallbacks callbacks for filtering the items
|
||||
* @param string $sort Property name used to sort the items.
|
||||
* Among them may be: '' (empty, no sorting), name,
|
||||
* fileext, size, tstamp and rw.
|
||||
* If a driver does not support the given property, it
|
||||
* should fall back to "name".
|
||||
* @param bool $sortRev TRUE to indicate reverse sorting (last to first)
|
||||
* @return list<string> of FileIdentifiers
|
||||
*/
|
||||
public function getFilesInFolder(
|
||||
string $folderIdentifier,
|
||||
int $start = 0,
|
||||
int $numberOfItems = 0,
|
||||
bool $recursive = false,
|
||||
array $filenameFilterCallbacks = [],
|
||||
string $sort = '',
|
||||
bool $sortRev = false
|
||||
): array;
|
||||
|
||||
/**
|
||||
* Returns the identifier of a folder inside the folder
|
||||
*
|
||||
* @param non-empty-string $folderName The name of the target folder
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @return non-empty-string folder identifier
|
||||
*/
|
||||
public function getFolderInFolder(string $folderName, string $folderIdentifier): string;
|
||||
|
||||
/**
|
||||
* Returns a list of folders inside the specified path
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @param int<0, max> $start
|
||||
* @param int<0, max> $numberOfItems
|
||||
* @param list<callable> $folderNameFilterCallbacks callbacks for filtering the items
|
||||
* @param string $sort Property name used to sort the items.
|
||||
* Among them may be: '' (empty, no sorting), name,
|
||||
* fileext, size, tstamp and rw.
|
||||
* If a driver does not support the given property, it
|
||||
* should fall back to "name".
|
||||
* @param bool $sortRev TRUE to indicate reverse sorting (last to first)
|
||||
* @return array<string|int, string> folder identifiers (where key and value are identical, but int-like identifiers
|
||||
* will get converted to int array keys)
|
||||
*/
|
||||
public function getFoldersInFolder(
|
||||
string $folderIdentifier,
|
||||
int $start = 0,
|
||||
int $numberOfItems = 0,
|
||||
bool $recursive = false,
|
||||
array $folderNameFilterCallbacks = [],
|
||||
string $sort = '',
|
||||
bool $sortRev = false
|
||||
): array;
|
||||
|
||||
/**
|
||||
* Returns the number of files inside the specified path
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @param list<callable> $filenameFilterCallbacks callbacks for filtering the items
|
||||
* @return int<0, max> Number of files in folder
|
||||
*/
|
||||
public function countFilesInFolder(string $folderIdentifier, bool $recursive = false, array $filenameFilterCallbacks = []): int;
|
||||
|
||||
/**
|
||||
* Returns the number of folders inside the specified path
|
||||
*
|
||||
* @param non-empty-string $folderIdentifier
|
||||
* @param list<callable> $folderNameFilterCallbacks callbacks for filtering the items
|
||||
* @return int<0, max> Number of folders in folder
|
||||
*/
|
||||
public function countFoldersInFolder(string $folderIdentifier, bool $recursive = false, array $folderNameFilterCallbacks = []): int;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Driver;
|
||||
|
||||
use TYPO3\CMS\Core\SingletonInterface;
|
||||
|
||||
/**
|
||||
* Registry for driver classes.
|
||||
*/
|
||||
class DriverRegistry implements SingletonInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $drivers = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $driverConfigurations = [];
|
||||
|
||||
/**
|
||||
* Creates this object by detecting all available drivers registered in $TYPO3_CONF_VARS.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$driverConfigurations = $GLOBALS['TYPO3_CONF_VARS']['SYS']['fal']['registeredDrivers'];
|
||||
foreach ($driverConfigurations as $shortName => $driverConfig) {
|
||||
$shortName = $shortName ?: $driverConfig['shortName'] ?? '';
|
||||
$this->registerDriverClass($driverConfig['class'] ?? '', $shortName, $driverConfig['label'] ?? '', $driverConfig['flexFormDS'] ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a driver class with an optional short name.
|
||||
*
|
||||
* @param string $className
|
||||
* @param string|null $shortName
|
||||
* @param string $label
|
||||
* @param string $flexFormDataStructurePathAndFilename
|
||||
* @return bool TRUE if registering succeeded
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function registerDriverClass($className, $shortName = null, $label = null, $flexFormDataStructurePathAndFilename = null)
|
||||
{
|
||||
// todo: Default of $shortName must be empty string, not null.
|
||||
$shortName = (string)$shortName;
|
||||
|
||||
// check if the class is available for TYPO3 before registering the driver
|
||||
if (!class_exists($className)) {
|
||||
throw new \InvalidArgumentException('Class ' . $className . ' does not exist.', 1314979197);
|
||||
}
|
||||
|
||||
if (!in_array(DriverInterface::class, class_implements($className) ?: [], true)) {
|
||||
throw new \InvalidArgumentException('Driver ' . $className . ' needs to implement the DriverInterface.', 1387619575);
|
||||
}
|
||||
if ($shortName === '') {
|
||||
$shortName = $className;
|
||||
}
|
||||
if (array_key_exists($shortName, $this->drivers)) {
|
||||
// Return immediately without changing configuration
|
||||
if ($this->drivers[$shortName] === $className) {
|
||||
return true;
|
||||
}
|
||||
throw new \InvalidArgumentException('Driver ' . $shortName . ' is already registered.', 1314979451);
|
||||
}
|
||||
$this->drivers[$shortName] = $className;
|
||||
$this->driverConfigurations[$shortName] = [
|
||||
'class' => $className,
|
||||
'shortName' => $shortName,
|
||||
'label' => $label,
|
||||
'flexFormDS' => $flexFormDataStructurePathAndFilename,
|
||||
];
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the TCA information so the registered drivers can be selected when creating a sys_file_storage
|
||||
* in the TYPO3 Backend.
|
||||
*/
|
||||
public function addDriversToTCA(): void
|
||||
{
|
||||
$driverFieldConfig = &$GLOBALS['TCA']['sys_file_storage']['columns']['driver']['config'];
|
||||
$types = &$GLOBALS['TCA']['sys_file_storage']['types'];
|
||||
foreach ($this->driverConfigurations as $driver) {
|
||||
$label = $driver['label'] ?: $driver['class'];
|
||||
$driverId = $driver['shortName'];
|
||||
$driverFieldConfig['items'][$driverId] = ['label' => $label, 'value' => $driverId];
|
||||
$types[$driverId] = $types['0'];
|
||||
if ($driver['flexFormDS']) {
|
||||
$types[$driverId]['columnsOverrides']['configuration']['config']['ds'] = $driver['flexFormDS'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a class name for a given class name or short name.
|
||||
*
|
||||
* @param string $shortName
|
||||
* @return string The class name
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getDriverClass($shortName)
|
||||
{
|
||||
if (in_array($shortName, $this->drivers) && class_exists($shortName)) {
|
||||
return $shortName;
|
||||
}
|
||||
if (!array_key_exists($shortName, $this->drivers)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Desired storage "' . $shortName . '" is not in the list of available storages.',
|
||||
1314085990
|
||||
);
|
||||
}
|
||||
return $this->drivers[$shortName];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given driver exists
|
||||
*
|
||||
* @param string $shortName Name of the driver
|
||||
* @return bool TRUE if the driver exists, FALSE otherwise
|
||||
*/
|
||||
public function driverExists($shortName)
|
||||
{
|
||||
return array_key_exists($shortName, $this->drivers);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
<?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\Resource\Driver;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* An interface FAL drivers have to implement to fulfil the needs
|
||||
* of streaming files using PSR-7 Response objects.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
interface StreamableDriverInterface
|
||||
{
|
||||
/**
|
||||
* Streams a file using a PSR-7 Response object.
|
||||
*/
|
||||
public function streamFile(string $identifier, array $properties): ResponseInterface;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?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\Resource\Enum;
|
||||
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Log\LogManager;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Enumeration for DuplicationBehavior
|
||||
*/
|
||||
enum DuplicationBehavior: string
|
||||
{
|
||||
/**
|
||||
* If a file is uploaded and another file with
|
||||
* the same name already exists, the new file
|
||||
* is renamed.
|
||||
*/
|
||||
case RENAME = 'rename';
|
||||
|
||||
/**
|
||||
* If a file is uploaded and another file with
|
||||
* the same name already exists, the old file
|
||||
* gets overwritten by the new file.
|
||||
*/
|
||||
case REPLACE = 'replace';
|
||||
|
||||
/**
|
||||
* If a file is uploaded and another file with
|
||||
* the same name already exists, the process is
|
||||
* aborted.
|
||||
*/
|
||||
case CANCEL = 'cancel';
|
||||
|
||||
/**
|
||||
* Return the default duplication behaviour action, set in TSconfig
|
||||
*/
|
||||
public static function getDefaultDuplicationBehaviour(?BackendUserAuthentication $backendUserAuthentication = null): DuplicationBehavior
|
||||
{
|
||||
if ($backendUserAuthentication === null) {
|
||||
return self::CANCEL;
|
||||
}
|
||||
$defaultAction = $backendUserAuthentication->getTSConfig()['options.']['file_list.']['uploader.']['defaultAction'] ?? '';
|
||||
|
||||
if ($defaultAction === '') {
|
||||
return self::CANCEL;
|
||||
}
|
||||
|
||||
$duplicationBehavior = self::tryFrom($defaultAction);
|
||||
if ($duplicationBehavior !== null) {
|
||||
return $duplicationBehavior;
|
||||
}
|
||||
|
||||
GeneralUtility::makeInstance(LogManager::class)
|
||||
->getLogger(__CLASS__)
|
||||
->warning('TSConfig: options.file_list.uploader.defaultAction contains an invalid value ("{value}"), fallback to default value: "{default}"', [
|
||||
'value' => $defaultAction,
|
||||
'default' => self::CANCEL->value,
|
||||
]);
|
||||
|
||||
return self::CANCEL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FolderInterface;
|
||||
|
||||
/**
|
||||
* Event that is fired after the default upload folder for a user was checked
|
||||
*/
|
||||
final class AfterDefaultUploadFolderWasResolvedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private ?FolderInterface $uploadFolder,
|
||||
private readonly ?int $pid,
|
||||
private readonly ?string $table,
|
||||
private readonly ?string $fieldName
|
||||
) {}
|
||||
|
||||
public function getUploadFolder(): ?FolderInterface
|
||||
{
|
||||
return $this->uploadFolder;
|
||||
}
|
||||
|
||||
public function setUploadFolder(FolderInterface $uploadFolder): void
|
||||
{
|
||||
$this->uploadFolder = $uploadFolder;
|
||||
}
|
||||
|
||||
public function getPid(): ?int
|
||||
{
|
||||
return $this->pid;
|
||||
}
|
||||
|
||||
public function getTable(): ?string
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
public function getFieldName(): ?string
|
||||
{
|
||||
return $this->fieldName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired after a file was added to the Resource Storage / Driver.
|
||||
*
|
||||
* Use case: Using listeners for this event allows to e.g. post-check permissions or
|
||||
* specific analysis of files like additional metadata analysis after adding them to TYPO3.
|
||||
*/
|
||||
final readonly class AfterFileAddedEvent
|
||||
{
|
||||
public function __construct(private FileInterface $file, private Folder $folder) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
}
|
||||
@@ -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\Resource\Event;
|
||||
|
||||
/**
|
||||
* This event is fired once an index was just added to the database (= indexed).
|
||||
*
|
||||
* Examples: Allows to additionally populate custom fields of the sys_file/sys_file_metadata database records.
|
||||
*/
|
||||
final readonly class AfterFileAddedToIndexEvent
|
||||
{
|
||||
public function __construct(private int $fileUid, private array $record) {}
|
||||
|
||||
public function getFileUid(): int
|
||||
{
|
||||
return $this->fileUid;
|
||||
}
|
||||
|
||||
public function getRecord(): array
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
/**
|
||||
* Event that is triggered after a file command has been processed. Can be used
|
||||
* to perform additional tasks for specific commands. For example, trigger a
|
||||
* custom indexer after a file has been uploaded.
|
||||
*/
|
||||
final readonly class AfterFileCommandProcessedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private array $command,
|
||||
private mixed $result,
|
||||
private string $conflictMode
|
||||
) {}
|
||||
|
||||
/**
|
||||
* A single command, e.g.
|
||||
*
|
||||
* ```
|
||||
* 'upload' => [
|
||||
* 'target' => '1:/some/folder/'
|
||||
* 'data' => '1'
|
||||
* ]
|
||||
* ```
|
||||
*
|
||||
* @return array<string, array<string, mixed>>
|
||||
*/
|
||||
public function getCommand(): array
|
||||
{
|
||||
return $this->command;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed The result - Depending on the performed action,
|
||||
* this could e.g. be a File or just a boolean.
|
||||
*/
|
||||
public function getResult(): mixed
|
||||
{
|
||||
return $this->result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The current conflict mode
|
||||
* @see DuplicationBehavior
|
||||
*/
|
||||
public function getConflictMode(): string
|
||||
{
|
||||
return $this->conflictMode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
|
||||
/**
|
||||
* This event is fired after the contents of a file got set / replaced.
|
||||
*
|
||||
* Examples: Listeners can analyze content for AI purposes within Extensions.
|
||||
*/
|
||||
final readonly class AfterFileContentsSetEvent
|
||||
{
|
||||
public function __construct(private FileInterface $file, private string $content) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired after a file was copied within a Resource Storage / Driver.
|
||||
* The folder represents the "target folder".
|
||||
*
|
||||
* Example: Listeners can sign up for listing duplicates using this event.
|
||||
*/
|
||||
final readonly class AfterFileCopiedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private FileInterface $file,
|
||||
private Folder $folder,
|
||||
private string $newFileIdentifier,
|
||||
private ?FileInterface $newFile
|
||||
) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function getNewFileIdentifier(): string
|
||||
{
|
||||
return $this->newFileIdentifier;
|
||||
}
|
||||
|
||||
public function getNewFile(): ?FileInterface
|
||||
{
|
||||
return $this->newFile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired before a file was created within a Resource Storage / Driver.
|
||||
* The folder represents the "target folder".
|
||||
*
|
||||
* Example: This allows to modify a file or check for an appropriate signature after a file was created in TYPO3.
|
||||
*/
|
||||
final readonly class AfterFileCreatedEvent
|
||||
{
|
||||
public function __construct(private string $fileName, private Folder $folder) {}
|
||||
|
||||
public function getFileName(): string
|
||||
{
|
||||
return $this->fileName;
|
||||
}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
}
|
||||
@@ -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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
|
||||
/**
|
||||
* This event is fired after a file was deleted.
|
||||
*
|
||||
* Example: If an extension provides additional functionality (e.g. variants), this event allows listener to also clean
|
||||
* up their custom handling. This can also be used for versioning of files.
|
||||
*/
|
||||
final readonly class AfterFileDeletedEvent
|
||||
{
|
||||
public function __construct(private FileInterface $file) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
/**
|
||||
* This event is fired once a file was just marked as missing in the database (sys_file).
|
||||
*
|
||||
* Example: If a file is marked as missing, listeners can try to recover a file. This can happen on specific setups
|
||||
* where editors also work via FTP.
|
||||
*/
|
||||
final readonly class AfterFileMarkedAsMissingEvent
|
||||
{
|
||||
public function __construct(private int $fileUid) {}
|
||||
|
||||
public function getFileUid(): int
|
||||
{
|
||||
return $this->fileUid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
/**
|
||||
* This event is fired once metadata of a file was added to the database, so it can be
|
||||
* enriched with more information.
|
||||
*/
|
||||
final class AfterFileMetaDataCreatedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private readonly int $fileUid,
|
||||
private readonly int $metaDataUid,
|
||||
private array $record
|
||||
) {}
|
||||
|
||||
public function getFileUid(): int
|
||||
{
|
||||
return $this->fileUid;
|
||||
}
|
||||
|
||||
public function getMetaDataUid(): int
|
||||
{
|
||||
return $this->metaDataUid;
|
||||
}
|
||||
|
||||
public function getRecord(): array
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
public function setRecord(array $record): void
|
||||
{
|
||||
$this->record = $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
/**
|
||||
* This event is fired once all metadata of a file was removed, in order to manage custom metadata that was
|
||||
* added previously
|
||||
*/
|
||||
final readonly class AfterFileMetaDataDeletedEvent
|
||||
{
|
||||
public function __construct(private int $fileUid) {}
|
||||
|
||||
public function getFileUid(): int
|
||||
{
|
||||
return $this->fileUid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
/**
|
||||
* This event is fired once metadata of a file was updated, in order to update custom metadata fields accordingly
|
||||
*/
|
||||
final readonly class AfterFileMetaDataUpdatedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private int $fileUid,
|
||||
private int $metaDataUid,
|
||||
private array $record
|
||||
) {}
|
||||
|
||||
public function getFileUid(): int
|
||||
{
|
||||
return $this->fileUid;
|
||||
}
|
||||
|
||||
public function getMetaDataUid(): int
|
||||
{
|
||||
return $this->metaDataUid;
|
||||
}
|
||||
|
||||
public function getRecord(): array
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\FolderInterface;
|
||||
|
||||
/**
|
||||
* This event is fired after a file was moved within a Resource Storage / Driver.
|
||||
* The folder represents the "target folder".
|
||||
*
|
||||
* Examples: Use this to update custom third party handlers that rely on specific paths.
|
||||
*/
|
||||
final readonly class AfterFileMovedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private FileInterface $file,
|
||||
private Folder $folder,
|
||||
private FolderInterface $originalFolder
|
||||
) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function getOriginalFolder(): FolderInterface
|
||||
{
|
||||
return $this->originalFolder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
use TYPO3\CMS\Core\Resource\ProcessedFile;
|
||||
|
||||
/**
|
||||
* This event is fired after a file object has been processed.
|
||||
*
|
||||
* This allows to further customize a file object's processed file.
|
||||
*/
|
||||
final class AfterFileProcessingEvent
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DriverInterface $driver,
|
||||
private ProcessedFile $processedFile,
|
||||
private readonly FileInterface $file,
|
||||
private readonly string $taskType,
|
||||
private readonly array $configuration
|
||||
) {}
|
||||
|
||||
public function getProcessedFile(): ProcessedFile
|
||||
{
|
||||
return $this->processedFile;
|
||||
}
|
||||
|
||||
public function setProcessedFile(ProcessedFile $processedFile): void
|
||||
{
|
||||
$this->processedFile = $processedFile;
|
||||
}
|
||||
|
||||
public function getDriver(): DriverInterface
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getTaskType(): string
|
||||
{
|
||||
return $this->taskType;
|
||||
}
|
||||
|
||||
public function getConfiguration(): array
|
||||
{
|
||||
return $this->configuration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
/**
|
||||
* This event is fired once a file was just removed in the database (sys_file).
|
||||
*
|
||||
* Example can be to further handle files and manage them separately outside of TYPO3's index.
|
||||
*/
|
||||
final readonly class AfterFileRemovedFromIndexEvent
|
||||
{
|
||||
public function __construct(private int $fileUid) {}
|
||||
|
||||
public function getFileUid(): int
|
||||
{
|
||||
return $this->fileUid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
|
||||
/**
|
||||
* This event is fired after a file was renamed in order to further process a file or filename
|
||||
* or update custom references to a file.
|
||||
*/
|
||||
final readonly class AfterFileRenamedEvent
|
||||
{
|
||||
public function __construct(private FileInterface $file, private ?string $targetFileName) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getTargetFileName(): ?string
|
||||
{
|
||||
return $this->targetFileName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
|
||||
/**
|
||||
* This event is fired after a file was replaced.
|
||||
*
|
||||
* Example: Further process a file or create variants, or index the contents of a file for AI analysis etc.
|
||||
*/
|
||||
final readonly class AfterFileReplacedEvent
|
||||
{
|
||||
public function __construct(private FileInterface $file, private string $localFilePath) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getLocalFilePath(): string
|
||||
{
|
||||
return $this->localFilePath;
|
||||
}
|
||||
}
|
||||
@@ -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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
|
||||
/**
|
||||
* This event is fired once an index was just updated inside the database (= indexed).
|
||||
* Custom listeners can update further index values when a file was updated.
|
||||
*/
|
||||
final readonly class AfterFileUpdatedInIndexEvent
|
||||
{
|
||||
public function __construct(
|
||||
private File $file,
|
||||
private array $properties,
|
||||
private array $updatedFields
|
||||
) {}
|
||||
|
||||
public function getFile(): File
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getRelevantProperties(): array
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
|
||||
public function getUpdatedFields(): array
|
||||
{
|
||||
return $this->updatedFields;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired after a folder was added to the Resource Storage / Driver.
|
||||
*
|
||||
* This allows to customize permissions or set up editor permissions automatically via listeners.
|
||||
*/
|
||||
final readonly class AfterFolderAddedEvent
|
||||
{
|
||||
public function __construct(private Folder $folder) {}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
}
|
||||
@@ -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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\FolderInterface;
|
||||
|
||||
/**
|
||||
* This event is fired after a folder was copied to the Resource Storage / Driver.
|
||||
*
|
||||
* Example: Custom listeners can analyze contents of a file or add custom permissions to a folder automatically.
|
||||
*/
|
||||
final readonly class AfterFolderCopiedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private Folder $folder,
|
||||
private Folder $targetParentFolder,
|
||||
private ?FolderInterface $targetFolder
|
||||
) {}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function getTargetParentFolder(): Folder
|
||||
{
|
||||
return $this->targetParentFolder;
|
||||
}
|
||||
|
||||
public function getTargetFolder(): ?FolderInterface
|
||||
{
|
||||
return $this->targetFolder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired after a folder was deleted. Custom listeners can then further clean up permissions or
|
||||
* third-party processed files with this event.
|
||||
*/
|
||||
final readonly class AfterFolderDeletedEvent
|
||||
{
|
||||
public function __construct(private Folder $folder, private bool $wasDeleted) {}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function isDeleted(): bool
|
||||
{
|
||||
return $this->wasDeleted;
|
||||
}
|
||||
}
|
||||
@@ -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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\FolderInterface;
|
||||
|
||||
/**
|
||||
* This event is fired after a folder was moved within the Resource Storage / Driver.
|
||||
*
|
||||
* Custom references can be updated via listeners of this event.
|
||||
*/
|
||||
final readonly class AfterFolderMovedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private Folder $folder,
|
||||
private Folder $targetParentFolder,
|
||||
private ?FolderInterface $targetFolder
|
||||
) {}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function getTargetParentFolder(): Folder
|
||||
{
|
||||
return $this->targetParentFolder;
|
||||
}
|
||||
|
||||
public function getTargetFolder(): ?FolderInterface
|
||||
{
|
||||
return $this->targetFolder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired after a folder was renamed.
|
||||
*
|
||||
* Examples: Add custom processing of folders or adjust permissions.
|
||||
*/
|
||||
final readonly class AfterFolderRenamedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private Folder $folder,
|
||||
private Folder $sourceFolder
|
||||
) {}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function getSourceFolder(): Folder
|
||||
{
|
||||
return $this->sourceFolder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\ResourceStorage;
|
||||
|
||||
/**
|
||||
* This event is fired after a resource object was built/created.
|
||||
*
|
||||
* Custom handlers can be initialized at this moment for any kind of source as well.
|
||||
*/
|
||||
final class AfterResourceStorageInitializationEvent
|
||||
{
|
||||
public function __construct(private ResourceStorage $storage) {}
|
||||
|
||||
public function getStorage(): ResourceStorage
|
||||
{
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
public function setStorage(ResourceStorage $storage): void
|
||||
{
|
||||
$this->storage = $storage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\ResourceStorage;
|
||||
|
||||
/**
|
||||
* This event is fired before a file is about to be added to the Resource Storage / Driver.
|
||||
*
|
||||
* This allows to do custom checks to a file or restrict access to a file before the file is added.
|
||||
*/
|
||||
final class BeforeFileAddedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private string $fileName,
|
||||
private readonly string $sourceFilePath,
|
||||
private readonly Folder $targetFolder,
|
||||
private readonly ResourceStorage $storage,
|
||||
private readonly DriverInterface $driver
|
||||
) {}
|
||||
|
||||
public function getFileName(): string
|
||||
{
|
||||
return $this->fileName;
|
||||
}
|
||||
|
||||
public function setFileName(string $fileName): void
|
||||
{
|
||||
$this->fileName = $fileName;
|
||||
}
|
||||
|
||||
public function getSourceFilePath(): string
|
||||
{
|
||||
return $this->sourceFilePath;
|
||||
}
|
||||
|
||||
public function getTargetFolder(): Folder
|
||||
{
|
||||
return $this->targetFolder;
|
||||
}
|
||||
|
||||
public function getStorage(): ResourceStorage
|
||||
{
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
public function getDriver(): DriverInterface
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
|
||||
/**
|
||||
* This event is fired before the contents of a file gets set / replaced.
|
||||
*
|
||||
* This allows to further analyze or modify the content of a file before it is written by the driver.
|
||||
*/
|
||||
final class BeforeFileContentsSetEvent
|
||||
{
|
||||
public function __construct(private readonly FileInterface $file, private string $content) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(string $content): void
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired before a file is about to be copied within a Resource Storage / Driver.
|
||||
* The folder represents the "target folder".
|
||||
*
|
||||
* This allows to further analyze or modify the file or metadata before it is written by the driver.
|
||||
*/
|
||||
final readonly class BeforeFileCopiedEvent
|
||||
{
|
||||
public function __construct(private FileInterface $file, private Folder $folder) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired before a file is about to be created within a Resource Storage / Driver.
|
||||
* The folder represents the "target folder".
|
||||
*
|
||||
* This allows to further analyze or modify the file or filename before it is written by the driver.
|
||||
*/
|
||||
final readonly class BeforeFileCreatedEvent
|
||||
{
|
||||
public function __construct(private string $fileName, private Folder $folder) {}
|
||||
|
||||
public function getFileName(): string
|
||||
{
|
||||
return $this->fileName;
|
||||
}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
|
||||
/**
|
||||
* This event is fired before a file is about to be deleted.
|
||||
*
|
||||
* Event listeners can clean up third-party references with this event.
|
||||
*/
|
||||
final readonly class BeforeFileDeletedEvent
|
||||
{
|
||||
public function __construct(private FileInterface $file) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired before a file is about to be moved within a Resource Storage / Driver.
|
||||
* The folder represents the "target folder".
|
||||
*/
|
||||
final readonly class BeforeFileMovedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private FileInterface $file,
|
||||
private Folder $folder,
|
||||
private string $targetFileName
|
||||
) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function getTargetFileName(): string
|
||||
{
|
||||
return $this->targetFileName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
use TYPO3\CMS\Core\Resource\ProcessedFile;
|
||||
|
||||
/**
|
||||
* This event is fired before a file object is processed.
|
||||
*
|
||||
* Allows to add further information or enrich the file before the processing is kicking in.
|
||||
*/
|
||||
final class BeforeFileProcessingEvent
|
||||
{
|
||||
public function __construct(
|
||||
private readonly DriverInterface $driver,
|
||||
private ProcessedFile $processedFile,
|
||||
private readonly FileInterface $file,
|
||||
private readonly string $taskType,
|
||||
private readonly array $configuration
|
||||
) {}
|
||||
|
||||
public function getProcessedFile(): ProcessedFile
|
||||
{
|
||||
return $this->processedFile;
|
||||
}
|
||||
|
||||
public function setProcessedFile(ProcessedFile $processedFile): void
|
||||
{
|
||||
$this->processedFile = $processedFile;
|
||||
}
|
||||
|
||||
public function getDriver(): DriverInterface
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getTaskType(): string
|
||||
{
|
||||
return $this->taskType;
|
||||
}
|
||||
|
||||
public function getConfiguration(): array
|
||||
{
|
||||
return $this->configuration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
|
||||
/**
|
||||
* This event is fired before a file is about to be renamed. Custom listeners can further rename the file
|
||||
* according to specific guidelines based on the project.
|
||||
*/
|
||||
final readonly class BeforeFileRenamedEvent
|
||||
{
|
||||
public function __construct(private FileInterface $file, private ?string $targetFileName) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getTargetFileName(): ?string
|
||||
{
|
||||
return $this->targetFileName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\FileInterface;
|
||||
|
||||
/**
|
||||
* This event is fired before a file is about to be replaced.
|
||||
* Custom listeners can check for file integrity or analyze the content of the file before it gets added.
|
||||
*/
|
||||
final readonly class BeforeFileReplacedEvent
|
||||
{
|
||||
public function __construct(private FileInterface $file, private string $localFilePath) {}
|
||||
|
||||
public function getFile(): FileInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function getLocalFilePath(): string
|
||||
{
|
||||
return $this->localFilePath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired before a folder is about to be added to the Resource Storage / Driver.
|
||||
* This allows to further specify folder names according to regulations for a specific project.
|
||||
*/
|
||||
final readonly class BeforeFolderAddedEvent
|
||||
{
|
||||
public function __construct(private Folder $parentFolder, private string $folderName) {}
|
||||
|
||||
public function getParentFolder(): Folder
|
||||
{
|
||||
return $this->parentFolder;
|
||||
}
|
||||
|
||||
public function getFolderName(): string
|
||||
{
|
||||
return $this->folderName;
|
||||
}
|
||||
}
|
||||
@@ -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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired before a folder is about to be copied to the Resource Storage / Driver.
|
||||
* Listeners could add deferred processing / queuing of large folders.
|
||||
*/
|
||||
final readonly class BeforeFolderCopiedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private Folder $folder,
|
||||
private Folder $targetParentFolder,
|
||||
private string $targetFolderName
|
||||
) {}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function getTargetParentFolder(): Folder
|
||||
{
|
||||
return $this->targetParentFolder;
|
||||
}
|
||||
|
||||
public function getTargetFolderName(): string
|
||||
{
|
||||
return $this->targetFolderName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired before a folder is about to be deleted.
|
||||
*
|
||||
* Listeners can use this event to clean up further external references to a folder / files in this folder.
|
||||
*/
|
||||
final readonly class BeforeFolderDeletedEvent
|
||||
{
|
||||
public function __construct(private Folder $folder) {}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired before a folder is about to be moved to the Resource Storage / Driver.
|
||||
* Listeners can be used to modify a folder name before it is actually moved or to ensure consistency
|
||||
* or specific rules when moving folders.
|
||||
*/
|
||||
final readonly class BeforeFolderMovedEvent
|
||||
{
|
||||
public function __construct(
|
||||
private Folder $folder,
|
||||
private Folder $targetParentFolder,
|
||||
private string $targetFolderName
|
||||
) {}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function getTargetParentFolder(): Folder
|
||||
{
|
||||
return $this->targetParentFolder;
|
||||
}
|
||||
|
||||
public function getTargetFolderName(): string
|
||||
{
|
||||
return $this->targetFolderName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
|
||||
/**
|
||||
* This event is fired before a folder is about to be renamed.
|
||||
* Listeners can be used to modify a folder name before it is actually moved or to ensure consistency
|
||||
* or specific rules when renaming folders.
|
||||
*/
|
||||
final readonly class BeforeFolderRenamedEvent
|
||||
{
|
||||
public function __construct(private Folder $folder, private string $targetName) {}
|
||||
|
||||
public function getFolder(): Folder
|
||||
{
|
||||
return $this->folder;
|
||||
}
|
||||
|
||||
public function getTargetName(): string
|
||||
{
|
||||
return $this->targetName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
/**
|
||||
* This event is fired before a resource object is actually built/created.
|
||||
*
|
||||
* Example: A database record can be enriched to add dynamic values to each resource (file/folder) before
|
||||
* creation of a storage
|
||||
*/
|
||||
final class BeforeResourceStorageInitializationEvent
|
||||
{
|
||||
public function __construct(private $storageUid, private $record, private ?string $fileIdentifier) {}
|
||||
|
||||
public function getStorageUid(): int
|
||||
{
|
||||
return $this->storageUid;
|
||||
}
|
||||
|
||||
public function setStorageUid(int $storageUid): void
|
||||
{
|
||||
$this->storageUid = $storageUid;
|
||||
}
|
||||
|
||||
public function getRecord(): array
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
public function setRecord(array $record): void
|
||||
{
|
||||
$this->record = $record;
|
||||
}
|
||||
|
||||
public function getFileIdentifier(): ?string
|
||||
{
|
||||
return $this->fileIdentifier;
|
||||
}
|
||||
|
||||
public function setFileIdentifier(?string $fileIdentifier): void
|
||||
{
|
||||
$this->fileIdentifier = $fileIdentifier;
|
||||
}
|
||||
}
|
||||
@@ -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\Resource\Event;
|
||||
|
||||
/**
|
||||
* Event that is called after a record has been loaded from database
|
||||
* Allows other places to do extension of metadata at runtime or
|
||||
* for example translation and workspace overlay.
|
||||
*/
|
||||
final class EnrichFileMetaDataEvent
|
||||
{
|
||||
public function __construct(private readonly int $fileUid, private readonly int $metaDataUid, private array $record) {}
|
||||
|
||||
public function getFileUid(): int
|
||||
{
|
||||
return $this->fileUid;
|
||||
}
|
||||
|
||||
public function getMetaDataUid(): int
|
||||
{
|
||||
return $this->metaDataUid;
|
||||
}
|
||||
|
||||
public function getRecord(): array
|
||||
{
|
||||
return $this->record;
|
||||
}
|
||||
|
||||
public function setRecord(array $record): void
|
||||
{
|
||||
$this->record = $record;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
|
||||
use TYPO3\CMS\Core\Resource\ResourceInterface;
|
||||
use TYPO3\CMS\Core\Resource\ResourceStorage;
|
||||
|
||||
/**
|
||||
* This event is fired before TYPO3 FAL's native URL generation for a Resource is instantiated.
|
||||
*
|
||||
* This allows for listeners to create custom links to certain files (e.g. restrictions) for creating
|
||||
* authorized deeplinks.
|
||||
*/
|
||||
final class GeneratePublicUrlForResourceEvent
|
||||
{
|
||||
private ?string $publicUrl = null;
|
||||
|
||||
public function __construct(
|
||||
private readonly ResourceInterface $resource,
|
||||
private readonly ResourceStorage $storage,
|
||||
private readonly DriverInterface $driver
|
||||
) {}
|
||||
|
||||
public function getResource(): ResourceInterface
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
public function getStorage(): ResourceStorage
|
||||
{
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
public function getDriver(): DriverInterface
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
public function getPublicUrl(): ?string
|
||||
{
|
||||
return $this->publicUrl;
|
||||
}
|
||||
|
||||
public function setPublicUrl(?string $publicUrl): void
|
||||
{
|
||||
$this->publicUrl = $publicUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use Psr\EventDispatcher\StoppableEventInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* Event that is triggered when a file should be dumped to the browser, allowing to perform custom
|
||||
* security/access checks when accessing a file through a direct link, and returning an alternative
|
||||
* Response.
|
||||
*
|
||||
* It is also possible to replace the file during this event, but not setting a response.
|
||||
*
|
||||
* As soon as a custom Response is added, the propagation is stopped.
|
||||
*/
|
||||
final class ModifyFileDumpEvent implements StoppableEventInterface
|
||||
{
|
||||
private ?ResponseInterface $response = null;
|
||||
|
||||
public function __construct(private ResourceInterface $file, private ServerRequestInterface $request) {}
|
||||
|
||||
public function getFile(): ResourceInterface
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
public function setFile(ResourceInterface $file): void
|
||||
{
|
||||
$this->file = $file;
|
||||
}
|
||||
|
||||
public function getRequest(): ServerRequestInterface
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
public function setResponse(ResponseInterface $response): void
|
||||
{
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
public function getResponse(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
public function isPropagationStopped(): bool
|
||||
{
|
||||
return $this->response !== null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?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\Resource\Event;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\ResourceStorage;
|
||||
|
||||
/**
|
||||
* This event is fired after a file name has been sanitized and before a file is added to FAL. Listeners can use this
|
||||
* event to modify the file name, and name the file according to naming conventions of a specific project.
|
||||
*/
|
||||
final class SanitizeFileNameEvent
|
||||
{
|
||||
public function __construct(
|
||||
private string $fileName,
|
||||
private readonly string $originalFileName,
|
||||
private readonly Folder $targetFolder,
|
||||
private readonly ResourceStorage $storage,
|
||||
private readonly DriverInterface $driver
|
||||
) {}
|
||||
|
||||
public function getFileName(): string
|
||||
{
|
||||
return $this->fileName;
|
||||
}
|
||||
|
||||
public function getOriginalFileName(): string
|
||||
{
|
||||
return $this->originalFileName;
|
||||
}
|
||||
|
||||
public function setFileName(string $fileName): void
|
||||
{
|
||||
$this->fileName = $fileName;
|
||||
}
|
||||
|
||||
public function getTargetFolder(): Folder
|
||||
{
|
||||
return $this->targetFolder;
|
||||
}
|
||||
|
||||
public function getStorage(): ResourceStorage
|
||||
{
|
||||
return $this->storage;
|
||||
}
|
||||
|
||||
public function getDriver(): DriverInterface
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class Exception extends \TYPO3\CMS\Core\Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
abstract class AbstractFileOperationException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class ExistingTargetFileNameException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class ExistingTargetFolderException extends Exception {}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
use TYPO3\CMS\Core\Resource\ProcessedFile;
|
||||
|
||||
/**
|
||||
* Exception indicating that a file is already processed
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class FileAlreadyProcessedException extends Exception
|
||||
{
|
||||
/**
|
||||
* @var ProcessedFile
|
||||
*/
|
||||
private $processedFile;
|
||||
|
||||
public function __construct(ProcessedFile $processedFile, int $code = 0)
|
||||
{
|
||||
$this->processedFile = $processedFile;
|
||||
parent::__construct(sprintf('File "%s" has already been processed', $processedFile->getIdentifier()), $code);
|
||||
}
|
||||
|
||||
public function getProcessedFile(): ProcessedFile
|
||||
{
|
||||
return $this->processedFile;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception to throw if a file does not exist
|
||||
*/
|
||||
class FileDoesNotExistException extends ResourceDoesNotExistException {}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class FileOperationErrorException extends AbstractFileOperationException {}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception to throw if a folder does not exist
|
||||
*/
|
||||
class FolderDoesNotExistException extends ResourceDoesNotExistException {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class IllegalFileExtensionException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class InsufficientFileAccessPermissionsException extends Exception {}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class InsufficientFileReadPermissionsException extends InsufficientFileAccessPermissionsException {}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class InsufficientFileWritePermissionsException extends InsufficientFileAccessPermissionsException {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class InsufficientFolderAccessPermissionsException extends Exception {}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class InsufficientFolderReadPermissionsException extends InsufficientFolderAccessPermissionsException {}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class InsufficientFolderWritePermissionsException extends InsufficientFolderAccessPermissionsException {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class InsufficientUserPermissionsException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the configuration
|
||||
*/
|
||||
class InvalidConfigurationException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the File
|
||||
*/
|
||||
class InvalidFileException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the File name
|
||||
*/
|
||||
class InvalidFileNameException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the Folder
|
||||
*/
|
||||
class InvalidFolderException extends Exception {}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the Hash
|
||||
* Is thrown for example when the driver returns an unexpected (non-string) hash value
|
||||
*/
|
||||
class InvalidHashException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the path
|
||||
*/
|
||||
class InvalidPathException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the file handling
|
||||
*/
|
||||
class InvalidTargetFolderException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* Thrown if an invalid uid is handled.
|
||||
*/
|
||||
class InvalidUidException extends Exception {}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with the Mount Point
|
||||
*/
|
||||
class NotInMountPointException extends Exception {}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
use TYPO3\CMS\Core\Resource\File;
|
||||
|
||||
/**
|
||||
* Exception indicating that an online media asset is already present in the target folder
|
||||
*/
|
||||
class OnlineMediaAlreadyExistsException extends Exception
|
||||
{
|
||||
public function __construct(
|
||||
private readonly File $onlineMedia,
|
||||
int $code = 0
|
||||
) {
|
||||
parent::__construct(
|
||||
sprintf('Online media asset "%s" does already exist in the target folder.', $onlineMedia->getName()),
|
||||
$code
|
||||
);
|
||||
}
|
||||
|
||||
public function getOnlineMedia(): File
|
||||
{
|
||||
return $this->onlineMedia;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception to throw if a resource (file/folder) does not exist
|
||||
*/
|
||||
class ResourceDoesNotExistException extends Exception {}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when something is wrong with fetching the permissions for a file or a folder.
|
||||
*
|
||||
* Extending \RuntimeException for backwards compatibility.
|
||||
*/
|
||||
class ResourcePermissionsUnavailableException extends Exception {}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when the upload goes wrong
|
||||
*/
|
||||
class UploadException extends AbstractFileOperationException {}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource\Exception;
|
||||
|
||||
/**
|
||||
* An exception when the size of the uploaded file has exceeded
|
||||
*/
|
||||
class UploadSizeException extends AbstractFileOperationException {}
|
||||
@@ -0,0 +1,405 @@
|
||||
<?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\Resource;
|
||||
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior;
|
||||
use TYPO3\CMS\Core\SystemResource\Identifier\FalResourceIdentifier;
|
||||
use TYPO3\CMS\Core\SystemResource\Publishing\SystemResourceUriGeneratorInterface;
|
||||
use TYPO3\CMS\Core\SystemResource\Type\PublicResourceInterface;
|
||||
use TYPO3\CMS\Core\SystemResource\Type\SystemResourceInterface;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* File representation in the file abstraction layer.
|
||||
*/
|
||||
class File extends AbstractFile implements PublicResourceInterface, SystemResourceInterface
|
||||
{
|
||||
/**
|
||||
* Contains the names of all properties that have been update since the
|
||||
* instantiation of this object
|
||||
*/
|
||||
protected array $updatedProperties = [];
|
||||
private ?MetaDataAspect $metaDataAspect = null;
|
||||
|
||||
protected string $identifier;
|
||||
|
||||
/**
|
||||
* Constructor for a file object. Should normally not be used directly, use
|
||||
* the corresponding factory methods instead.
|
||||
*/
|
||||
public function __construct(array $fileData, ResourceStorage $storage, array $metaData = [])
|
||||
{
|
||||
$this->identifier = $fileData['identifier'] ?? '';
|
||||
$this->name = $fileData['name'] ?? '';
|
||||
$this->properties = $fileData;
|
||||
$this->storage = $storage;
|
||||
|
||||
if ($metaData !== []) {
|
||||
$this->getMetaData()->add($metaData);
|
||||
}
|
||||
}
|
||||
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return $this->identifier;
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* VARIOUS FILE PROPERTY GETTERS
|
||||
*******************************/
|
||||
/**
|
||||
* Returns a property value
|
||||
*
|
||||
* @param non-empty-string $key
|
||||
*/
|
||||
public function getProperty(string $key): mixed
|
||||
{
|
||||
if (parent::hasProperty($key)) {
|
||||
return parent::getProperty($key);
|
||||
}
|
||||
return $this->getMetaData()[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames this file.
|
||||
*
|
||||
* @param non-empty-string $newName The new file name
|
||||
*/
|
||||
public function rename(string $newName, DuplicationBehavior $conflictMode = DuplicationBehavior::RENAME): FileInterface
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821482);
|
||||
}
|
||||
|
||||
return $this->getStorage()->renameFile($this, $newName, $conflictMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies this file into a target folder
|
||||
* @param Folder $targetFolder Folder to copy file into.
|
||||
* @param string|null $targetFileName an optional destination fileName
|
||||
*
|
||||
* @return self The new (copied) file.
|
||||
*/
|
||||
public function copyTo(Folder $targetFolder, ?string $targetFileName = null, DuplicationBehavior $conflictMode = DuplicationBehavior::RENAME): FileInterface
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821483);
|
||||
}
|
||||
|
||||
return $targetFolder->getStorage()->copyFile($this, $targetFolder, $targetFileName, $conflictMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the file into the target folder
|
||||
*
|
||||
* @param Folder $targetFolder Folder to move file into.
|
||||
* @param string|null $targetFileName an optional destination fileName
|
||||
* @param DuplicationBehavior $conflictMode
|
||||
*
|
||||
* @return FileInterface This file object, with updated properties.
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function moveTo(Folder $targetFolder, ?string $targetFileName = null, DuplicationBehavior $conflictMode = DuplicationBehavior::RENAME): FileInterface
|
||||
{
|
||||
if ($this->deleted) {
|
||||
throw new \RuntimeException('File has been deleted.', 1329821484);
|
||||
}
|
||||
|
||||
return $targetFolder->getStorage()->moveFile($this, $targetFolder, $targetFileName, $conflictMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the file has a (metadata) property which
|
||||
* can be retrieved by "getProperty"
|
||||
*/
|
||||
public function hasProperty(string $key): bool
|
||||
{
|
||||
if (!parent::hasProperty($key)) {
|
||||
return isset($this->getMetaData()[$key]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the properties of this object.
|
||||
*/
|
||||
public function getProperties(): array
|
||||
{
|
||||
return array_merge(
|
||||
parent::getProperties(),
|
||||
array_diff_key($this->getMetaData()->get(), parent::getProperties()),
|
||||
[
|
||||
'metadata_uid' => $this->getMetaData()->get()['uid'] ?? 0,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/******************
|
||||
* CONTENTS RELATED
|
||||
******************/
|
||||
/**
|
||||
* Get the contents of this file
|
||||
*/
|
||||
public function getContents(): string
|
||||
{
|
||||
return $this->getStorage()->getFileContents($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets SHA1 hash.
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getSha1(): string
|
||||
{
|
||||
if (empty($this->properties['sha1'])) {
|
||||
$this->properties['sha1'] = parent::getSha1();
|
||||
}
|
||||
return $this->properties['sha1'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the current file contents with the given string
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setContents(string $contents): self
|
||||
{
|
||||
$this->getStorage()->setFileContents($this, $contents);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/***********************
|
||||
* INDEX RELATED METHODS
|
||||
***********************/
|
||||
/**
|
||||
* Returns TRUE if this file is indexed
|
||||
*/
|
||||
public function isIndexed(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the properties of this file, e.g. after re-indexing or moving it.
|
||||
* By default, only properties that exist as a key in the $properties array
|
||||
* are overwritten. If you want to explicitly unset a property, set the
|
||||
* corresponding key to NULL in the array.
|
||||
*
|
||||
* NOTE: This method should not be called from outside the File Abstraction Layer (FAL)!
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function updateProperties(array $properties): void
|
||||
{
|
||||
// Setting identifier and name to update values; we have to do this
|
||||
// here because we might need a new identifier when loading
|
||||
// (and thus possibly indexing) a file.
|
||||
if (isset($properties['identifier'])) {
|
||||
$this->identifier = $properties['identifier'];
|
||||
}
|
||||
if (isset($properties['name'])) {
|
||||
$this->name = $properties['name'];
|
||||
}
|
||||
|
||||
if (isset($properties['uid']) && $this->properties['uid'] != 0) {
|
||||
unset($properties['uid']);
|
||||
}
|
||||
foreach ($properties as $key => $value) {
|
||||
if (!isset($this->properties[$key]) || $this->properties[$key] !== $value) {
|
||||
if (!in_array($key, $this->updatedProperties)) {
|
||||
$this->updatedProperties[] = $key;
|
||||
}
|
||||
$this->properties[$key] = $value;
|
||||
}
|
||||
}
|
||||
// If the mime_type property should be updated and it was changed also update the type.
|
||||
if (array_key_exists('mime_type', $properties) && in_array('mime_type', $this->updatedProperties)) {
|
||||
$this->updatedProperties[] = 'type';
|
||||
unset($this->properties['type']);
|
||||
$this->getType();
|
||||
}
|
||||
if (array_key_exists('storage', $properties) && in_array('storage', $this->updatedProperties)) {
|
||||
$this->storage = GeneralUtility::makeInstance(StorageRepository::class)->findByUid((int)$properties['storage']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names of all properties that have been updated in this record
|
||||
*/
|
||||
public function getUpdatedProperties(): array
|
||||
{
|
||||
return $this->updatedProperties;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* STORAGE AND MANAGEMENT RELATED METHODS
|
||||
****************************************/
|
||||
/**
|
||||
* Check if a file operation (= action) is allowed for this file
|
||||
*
|
||||
* @param string $action can be read, write, delete
|
||||
*/
|
||||
public function checkActionPermission(string $action): bool
|
||||
{
|
||||
return $this->getStorage()->checkFileActionPermission($action, $this);
|
||||
}
|
||||
|
||||
/*****************
|
||||
* SPECIAL METHODS
|
||||
*****************/
|
||||
/**
|
||||
* Creates a MD5 hash checksum based on the combined identifier of the file,
|
||||
* the files' mimetype and the systems' encryption key.
|
||||
* used to generate a thumbnail, and this hash is checked if valid
|
||||
*
|
||||
* @return string the MD5 hash
|
||||
*/
|
||||
public function calculateChecksum(): string
|
||||
{
|
||||
return md5(
|
||||
$this->getCombinedIdentifier() . '|'
|
||||
. $this->getMimeType() . '|'
|
||||
. $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a modified version of the file.
|
||||
*
|
||||
* @param string $taskType The task type of this processing
|
||||
* @param array $configuration the processing configuration, see manual for that
|
||||
*/
|
||||
public function process(string $taskType, array $configuration): ProcessedFile
|
||||
{
|
||||
return $this->getStorage()->processFile($this, $taskType, $configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the file.
|
||||
* (This is used by the generic listing module vidi when displaying file records.)
|
||||
*
|
||||
* @return array<non-empty-string, mixed> Array of main data of the file. Don't rely on all data to be present here, it's just a selection of the most relevant information.
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
$array = [
|
||||
'id' => $this->getCombinedIdentifier(),
|
||||
'name' => $this->getName(),
|
||||
'extension' => $this->getExtension(),
|
||||
'type' => $this->getType(),
|
||||
'mimetype' => $this->getMimeType(),
|
||||
'size' => $this->getSize(),
|
||||
'url' => $this->getPublicUrl(),
|
||||
'indexed' => true,
|
||||
'uid' => $this->getUid(),
|
||||
'permissions' => [
|
||||
'read' => $this->checkActionPermission('read'),
|
||||
'write' => $this->checkActionPermission('write'),
|
||||
'delete' => $this->checkActionPermission('delete'),
|
||||
],
|
||||
'checksum' => $this->calculateChecksum(),
|
||||
];
|
||||
foreach ($this->properties as $key => $value) {
|
||||
$array[$key] = $value;
|
||||
}
|
||||
$stat = $this->getStorage()->getFileInfo($this);
|
||||
foreach ($stat as $key => $value) {
|
||||
$array[$key] = $value;
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function isMissing(): bool
|
||||
{
|
||||
return (bool)$this->getProperty('missing');
|
||||
}
|
||||
|
||||
public function setMissing(bool $missing): void
|
||||
{
|
||||
$this->updateProperties(['missing' => $missing ? 1 : 0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a publicly accessible URL for this file
|
||||
* When file is marked as missing or deleted no url is returned
|
||||
*
|
||||
* WARNING: Access to the file may be restricted by further means, e.g. some
|
||||
* web-based authentication. You have to take care of this yourself.
|
||||
*/
|
||||
public function getPublicUrl(): ?string
|
||||
{
|
||||
if ($this->isMissing() || $this->deleted) {
|
||||
return null;
|
||||
}
|
||||
return $this->getStorage()->getPublicUrl($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal Only for use in Repositories and indexer
|
||||
*/
|
||||
public function _getPropertyRaw(string $key): mixed
|
||||
{
|
||||
return parent::getProperty($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the metadata of a file in an encapsulated aspect
|
||||
*/
|
||||
public function getMetaData(): MetaDataAspect
|
||||
{
|
||||
if ($this->metaDataAspect === null) {
|
||||
$this->metaDataAspect = GeneralUtility::makeInstance(MetaDataAspect::class, $this);
|
||||
}
|
||||
return $this->metaDataAspect;
|
||||
}
|
||||
|
||||
/***********************************
|
||||
* System Resources implementation *
|
||||
***********************************/
|
||||
public function getHash(): string
|
||||
{
|
||||
return $this->getSha1();
|
||||
}
|
||||
|
||||
public function getPublicUri(SystemResourceUriGeneratorInterface $uriGenerator): UriInterface
|
||||
{
|
||||
return $uriGenerator->generateForFile($this);
|
||||
}
|
||||
|
||||
public function isPublished(): bool
|
||||
{
|
||||
return $this->getStorage()->isPublic();
|
||||
}
|
||||
|
||||
public function getResourceIdentifier(): string
|
||||
{
|
||||
return (string)(new FalResourceIdentifier(
|
||||
(string)$this->getStorage()->getUid(),
|
||||
$this->getIdentifier(),
|
||||
sprintf('File: uid: %d, identifier: %s', $this->getUid(), $this->getIdentifier()),
|
||||
));
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->getResourceIdentifier();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* 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\Resource;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Core\Collection\AbstractRecordCollection;
|
||||
use TYPO3\CMS\Core\Collection\CollectionInterface;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
|
||||
use TYPO3\CMS\Core\Http\ApplicationType;
|
||||
use TYPO3\CMS\Core\Resource\Collection\FileCollectionRegistry;
|
||||
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Repository for accessing file collections stored in the database
|
||||
*/
|
||||
readonly class FileCollectionRepository
|
||||
{
|
||||
public function __construct(
|
||||
private ConnectionPool $connectionPool,
|
||||
private FileCollectionRegistry $fileCollectionRegistry
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Finds a record collection by uid.
|
||||
*
|
||||
* @throws Exception\ResourceDoesNotExistException
|
||||
*/
|
||||
public function findByUid(int $uid): ?CollectionInterface
|
||||
{
|
||||
$object = null;
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_file_collection');
|
||||
if ($this->isFrontendRequest()) {
|
||||
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
|
||||
} else {
|
||||
$queryBuilder->getRestrictions()->removeAll()
|
||||
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
|
||||
}
|
||||
$data = $queryBuilder->select('*')
|
||||
->from('sys_file_collection')
|
||||
->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, Connection::PARAM_INT)))
|
||||
->executeQuery()
|
||||
->fetchAssociative();
|
||||
if (is_array($data)) {
|
||||
$object = $this->createDomainObject($data);
|
||||
}
|
||||
if ($object === null) {
|
||||
throw new ResourceDoesNotExistException('Could not find row with uid "' . $uid . '" in table "sys_file_collection"', 1314354066);
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds record collection by type.
|
||||
*
|
||||
* @return CollectionInterface[]|null
|
||||
*/
|
||||
public function findByType(string $type): ?array
|
||||
{
|
||||
$expressionBuilder = $this->connectionPool->getQueryBuilderForTable('sys_file_collection')->expr();
|
||||
return $this->queryMultipleRecords([
|
||||
$expressionBuilder->eq('type', $expressionBuilder->literal($type)),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all record collections.
|
||||
*
|
||||
* @return CollectionInterface[]|null
|
||||
*/
|
||||
public function findAll(): ?array
|
||||
{
|
||||
return $this->queryMultipleRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries for multiple records for the given conditions.
|
||||
*
|
||||
* @param array $conditions Conditions concatenated with AND for query
|
||||
* @return CollectionInterface[]|null
|
||||
*/
|
||||
protected function queryMultipleRecords(array $conditions = []): ?array
|
||||
{
|
||||
$result = null;
|
||||
$queryBuilder = $this->connectionPool->getQueryBuilderForTable('sys_file_collection');
|
||||
$queryBuilder->getRestrictions()->removeAll()
|
||||
->add(GeneralUtility::makeInstance(DeletedRestriction::class));
|
||||
$queryBuilder->select('*')->from('sys_file_collection');
|
||||
if (!empty($conditions)) {
|
||||
$queryBuilder->where(...$conditions);
|
||||
}
|
||||
$data = $queryBuilder->executeQuery()->fetchAllAssociative();
|
||||
if (!empty($data)) {
|
||||
$result = $this->createMultipleDomainObjects($data);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates multiple record collection domain objects.
|
||||
*
|
||||
* @param array $data Array of multiple database records to be reconstituted
|
||||
* @return CollectionInterface[]
|
||||
*/
|
||||
protected function createMultipleDomainObjects(array $data): array
|
||||
{
|
||||
$collections = [];
|
||||
foreach ($data as $collection) {
|
||||
$collections[] = $this->createDomainObject($collection);
|
||||
}
|
||||
return $collections;
|
||||
}
|
||||
|
||||
protected function isFrontendRequest(): bool
|
||||
{
|
||||
if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
|
||||
&& ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a record collection domain object.
|
||||
*
|
||||
* @param array $record Database record to be reconstituted
|
||||
*/
|
||||
protected function createDomainObject(array $record): CollectionInterface
|
||||
{
|
||||
/** @var AbstractRecordCollection $className */
|
||||
$className = $this->fileCollectionRegistry->getFileCollectionClass($record['type']);
|
||||
return $className::create($record);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?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\Resource;
|
||||
|
||||
/**
|
||||
* Interface for a file object. This can be any kind of file object,
|
||||
* e.g. a processed file (which is not a FAL file), or a file reference object,
|
||||
* which is a decorator around a "File" object, but of course without any additional
|
||||
* file on the file system.
|
||||
*/
|
||||
interface FileInterface extends ResourceInterface
|
||||
{
|
||||
/*******************************
|
||||
* VARIOUS FILE PROPERTY GETTERS
|
||||
*******************************/
|
||||
/**
|
||||
* Returns true if the given key exists for this file.
|
||||
*
|
||||
* @param non-empty-string $key
|
||||
*/
|
||||
public function hasProperty(string $key): bool;
|
||||
|
||||
/**
|
||||
* Get the value of the $key property.
|
||||
*
|
||||
* @param non-empty-string $key
|
||||
*/
|
||||
public function getProperty(string $key): mixed;
|
||||
|
||||
/**
|
||||
* MUST return the size of the file as unsigned int i.e. 0-max.
|
||||
*
|
||||
* In case of errors, e.g. when the file is deleted or not readable,
|
||||
* this method MAY either throw an Exception or return 0.
|
||||
*
|
||||
* @return int<0, max>
|
||||
*/
|
||||
public function getSize(): int;
|
||||
|
||||
/**
|
||||
* Returns the Sha1 of this file
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getSha1(): string;
|
||||
|
||||
/**
|
||||
* Returns the basename (the name without extension) of this file.
|
||||
*/
|
||||
public function getNameWithoutExtension(): string;
|
||||
|
||||
/**
|
||||
* Get the file extension
|
||||
*/
|
||||
public function getExtension(): string;
|
||||
|
||||
/**
|
||||
* Get the MIME type of this file
|
||||
*
|
||||
* @return non-empty-string mime type
|
||||
*/
|
||||
public function getMimeType(): string;
|
||||
|
||||
/**
|
||||
* Returns the modification time of the file as Unix timestamp
|
||||
*/
|
||||
public function getModificationTime(): int;
|
||||
|
||||
/**
|
||||
* Returns the creation time of the file as Unix timestamp
|
||||
*/
|
||||
public function getCreationTime(): int;
|
||||
|
||||
/******************
|
||||
* CONTENTS RELATED
|
||||
******************/
|
||||
/**
|
||||
* Get the contents of this file
|
||||
*/
|
||||
public function getContents(): string;
|
||||
|
||||
/**
|
||||
* Replace the current file contents with the given string.
|
||||
*
|
||||
* @todo: Consider to remove this function from the interface, as its
|
||||
* implementation in FileInUse could cause unforseen side-effects by setting
|
||||
* contents on the original file instead of just on the Usage of the file.
|
||||
* @todo: At the same time, it could be considered whether to make the whole
|
||||
* interface a read-only FileInterface, so that all file management and
|
||||
* modification functions are removed...
|
||||
* @return $this
|
||||
*/
|
||||
public function setContents(string $contents): self;
|
||||
|
||||
/****************************************
|
||||
* STORAGE AND MANAGEMENT RELATED METHODS
|
||||
****************************************/
|
||||
/**
|
||||
* Deletes this file from its storage. This also means that this object becomes useless.
|
||||
*/
|
||||
public function delete(): bool;
|
||||
|
||||
/*****************
|
||||
* SPECIAL METHODS
|
||||
*****************/
|
||||
/**
|
||||
* Returns a publicly accessible URL for this file
|
||||
*
|
||||
* WARNING: Access to the file may be restricted by further means, e.g.
|
||||
* some web-based authentication. You have to take care of this yourself.
|
||||
*
|
||||
* @return non-empty-string|null NULL if file is missing or deleted, the generated url otherwise
|
||||
*/
|
||||
public function getPublicUrl(): ?string;
|
||||
|
||||
/**
|
||||
* Returns TRUE if this file is indexed
|
||||
*/
|
||||
public function isIndexed(): bool;
|
||||
|
||||
/**
|
||||
* Returns a path to a local version of this file to process it locally (e.g. with some system tool).
|
||||
* If the file is normally located on a remote storages, this creates a local copy.
|
||||
* If the file is already on the local system, this only makes a new copy if $writable is set to TRUE.
|
||||
*
|
||||
* @param bool $writable Set this to FALSE if you only want to do read operations on the file.
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getForLocalProcessing(bool $writable = true): string;
|
||||
|
||||
/**
|
||||
* Returns an array representation of the file.
|
||||
* (This is used by the generic listing module vidi when displaying file records.)
|
||||
*
|
||||
* @return array<string, mixed> Array of main data of the file. Don't rely on all data to be present here, it's just a selection of the most relevant information.
|
||||
*/
|
||||
public function toArray(): array;
|
||||
}
|
||||
@@ -0,0 +1,508 @@
|
||||
<?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\Resource;
|
||||
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\ReferenceIndex;
|
||||
use TYPO3\CMS\Core\Resource\Enum\DuplicationBehavior;
|
||||
use TYPO3\CMS\Core\Schema\Capability\TcaSchemaCapability;
|
||||
use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
|
||||
use TYPO3\CMS\Core\Utility\ArrayUtility;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Representation of a specific usage of a file with possibilities to override certain
|
||||
* properties of the original file just for this usage of the file.
|
||||
*
|
||||
* It acts as a decorator over the original file in the way that most method calls are
|
||||
* directly passed along to the original file object.
|
||||
*
|
||||
* All file related methods are directly passed along; only meta-data functionality is adopted
|
||||
* in this decorator class to prioritize possible overrides for the metadata for this specific usage
|
||||
* of the file.
|
||||
*/
|
||||
class FileReference implements FileInterface
|
||||
{
|
||||
/**
|
||||
* Various properties of the FileReference. Note that these information can be different
|
||||
* to the ones found in the originalFile.
|
||||
*/
|
||||
protected array $propertiesOfFileReference;
|
||||
|
||||
/**
|
||||
* Reference to the original File object underlying this FileReference.
|
||||
*/
|
||||
protected File $originalFile;
|
||||
|
||||
/**
|
||||
* Properties merged with the parent object (File) if
|
||||
* the value is not defined (NULL). Thus, FileReference properties act
|
||||
* as overlays for the defined File properties.
|
||||
*/
|
||||
protected array $mergedProperties = [];
|
||||
|
||||
/**
|
||||
* Constructor for a file in use object. Should normally not be used
|
||||
* directly, use the corresponding factory methods instead.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(array $fileReferenceData, ?ResourceFactory $factory = null)
|
||||
{
|
||||
$this->propertiesOfFileReference = $fileReferenceData;
|
||||
if (!$fileReferenceData['uid_local']) {
|
||||
throw new \InvalidArgumentException('Incorrect reference to original file given for FileReference.', 1300098528);
|
||||
}
|
||||
$this->originalFile = $this->getFileObject((int)$fileReferenceData['uid_local'], $factory);
|
||||
}
|
||||
|
||||
private function getFileObject(int $uidLocal, ?ResourceFactory $factory = null): File
|
||||
{
|
||||
if ($factory === null) {
|
||||
$factory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||
}
|
||||
return $factory->getFileObject($uidLocal);
|
||||
}
|
||||
|
||||
/*******************************
|
||||
* VARIOUS FILE PROPERTY GETTERS
|
||||
*******************************/
|
||||
/**
|
||||
* Returns true if the given key exists for this file.
|
||||
*
|
||||
* @param non-empty-string $key The property to be looked up
|
||||
*/
|
||||
public function hasProperty(string $key): bool
|
||||
{
|
||||
return array_key_exists($key, $this->getProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a property, falling back to values of the parent.
|
||||
*
|
||||
* @param non-empty-string $key The property to be looked up
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getProperty(string $key): mixed
|
||||
{
|
||||
if (!$this->hasProperty($key)) {
|
||||
throw new \InvalidArgumentException('Property "' . $key . '" was not found in file reference or original file.', 1314226805);
|
||||
}
|
||||
$properties = $this->getProperties();
|
||||
return $properties[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a property of the file reference.
|
||||
*
|
||||
* @param string $key The property to be looked up
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function getReferenceProperty(string $key): mixed
|
||||
{
|
||||
if (!array_key_exists($key, $this->propertiesOfFileReference)) {
|
||||
throw new \InvalidArgumentException('Property "' . $key . '" of file reference was not found.', 1360684914);
|
||||
}
|
||||
return $this->propertiesOfFileReference[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all properties, falling back to values of the parent.
|
||||
*/
|
||||
public function getProperties(): array
|
||||
{
|
||||
if (empty($this->mergedProperties)) {
|
||||
$this->mergedProperties = $this->propertiesOfFileReference;
|
||||
ArrayUtility::mergeRecursiveWithOverrule(
|
||||
$this->mergedProperties,
|
||||
$this->originalFile->getProperties(),
|
||||
true,
|
||||
true,
|
||||
false
|
||||
);
|
||||
array_walk($this->mergedProperties, $this->restoreNonNullValuesCallback(...));
|
||||
}
|
||||
return $this->mergedProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to handle the NULL value feature
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $key
|
||||
*/
|
||||
protected function restoreNonNullValuesCallback(&$value, $key)
|
||||
{
|
||||
if (array_key_exists($key, $this->propertiesOfFileReference) && $this->propertiesOfFileReference[$key] !== null) {
|
||||
$value = $this->propertiesOfFileReference[$key];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all properties of the file reference.
|
||||
*/
|
||||
public function getReferenceProperties(): array
|
||||
{
|
||||
return $this->propertiesOfFileReference;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->originalFile->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title text to this image
|
||||
*
|
||||
* @todo Possibly move this to the image domain object instead
|
||||
*/
|
||||
public function getTitle(): string
|
||||
{
|
||||
return (string)$this->getProperty('title');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alternative text to this image
|
||||
*
|
||||
* @todo Possibly move this to the image domain object instead
|
||||
*/
|
||||
public function getAlternative(): string
|
||||
{
|
||||
return (string)$this->getProperty('alternative');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the description text to this file
|
||||
*
|
||||
* @todo Possibly move this to the image domain object instead
|
||||
*/
|
||||
public function getDescription(): string
|
||||
{
|
||||
return (string)$this->getProperty('description');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the link that should be active when clicking on this image
|
||||
*
|
||||
* @todo Move this to the image domain object instead
|
||||
*/
|
||||
public function getLink(): string
|
||||
{
|
||||
return $this->propertiesOfFileReference['link'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uid of this File In Use
|
||||
*/
|
||||
public function getUid(): int
|
||||
{
|
||||
return (int)$this->propertiesOfFileReference['uid'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int<0, max>
|
||||
*/
|
||||
public function getSize(): int
|
||||
{
|
||||
return $this->originalFile->getSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Sha1 of this file
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getSha1(): string
|
||||
{
|
||||
return $this->originalFile->getSha1();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file extension of this file
|
||||
*
|
||||
* @return string The file extension
|
||||
*/
|
||||
public function getExtension(): string
|
||||
{
|
||||
return $this->originalFile->getExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the basename (the name without extension) of this file.
|
||||
*/
|
||||
public function getNameWithoutExtension(): string
|
||||
{
|
||||
return $this->originalFile->getNameWithoutExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MIME type of this file
|
||||
*
|
||||
* @return non-empty-string mime type
|
||||
*/
|
||||
public function getMimeType(): string
|
||||
{
|
||||
return $this->originalFile->getMimeType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the modification time of the file as Unix timestamp
|
||||
*/
|
||||
public function getModificationTime(): int
|
||||
{
|
||||
return $this->originalFile->getModificationTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the creation time of the file as Unix timestamp
|
||||
*/
|
||||
public function getCreationTime(): int
|
||||
{
|
||||
return $this->originalFile->getCreationTime();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fileType of this file
|
||||
*/
|
||||
public function getType(): int
|
||||
{
|
||||
return $this->originalFile->getType();
|
||||
}
|
||||
|
||||
public function isType(FileType $fileType): bool
|
||||
{
|
||||
return $this->getFileType() === $fileType;
|
||||
}
|
||||
|
||||
public function getFileType(): FileType
|
||||
{
|
||||
return $this->originalFile->getFileType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if file is marked as missing by indexer
|
||||
*/
|
||||
public function isMissing(): bool
|
||||
{
|
||||
return (bool)$this->originalFile->getProperty('missing');
|
||||
}
|
||||
|
||||
/******************
|
||||
* CONTENTS RELATED
|
||||
******************/
|
||||
/**
|
||||
* Get the contents of this file
|
||||
*/
|
||||
public function getContents(): string
|
||||
{
|
||||
return $this->originalFile->getContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the current file contents with the given string
|
||||
*
|
||||
* @param string $contents The contents to write to the file.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setContents(string $contents): self
|
||||
{
|
||||
$this->originalFile->setContents($contents);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/****************************************
|
||||
* STORAGE AND MANAGEMENT RELATED METHODS
|
||||
****************************************/
|
||||
/**
|
||||
* Get the storage the original file is located in
|
||||
*/
|
||||
public function getStorage(): ResourceStorage
|
||||
{
|
||||
return $this->originalFile->getStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of the underlying original file
|
||||
*
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
return $this->originalFile->getIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a combined identifier of the underlying original file
|
||||
*
|
||||
* @return string Combined storage and file identifier, e.g. StorageUID:path/and/fileName.png
|
||||
*/
|
||||
public function getCombinedIdentifier(): string
|
||||
{
|
||||
return $this->originalFile->getCombinedIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes only this particular FileReference from the persistence layer (table: sys_file_reference)
|
||||
* and leaves the original file untouched.
|
||||
*/
|
||||
public function delete(): bool
|
||||
{
|
||||
$schema = GeneralUtility::makeInstance(TcaSchemaFactory::class)->get('sys_file_reference');
|
||||
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
|
||||
if ($schema->hasCapability(TcaSchemaCapability::SoftDelete)) {
|
||||
$softDeleteFieldName = $schema->getCapability(TcaSchemaCapability::SoftDelete)->getFieldName();
|
||||
$affectedRows = $connectionPool->getConnectionForTable('sys_file_reference')
|
||||
->update(
|
||||
'sys_file_reference',
|
||||
[
|
||||
$softDeleteFieldName => 1,
|
||||
],
|
||||
[
|
||||
'uid' => $this->getUid(),
|
||||
]
|
||||
);
|
||||
} else {
|
||||
$affectedRows = $connectionPool->getConnectionForTable('sys_file_reference')
|
||||
->delete(
|
||||
'sys_file_reference',
|
||||
[
|
||||
'uid' => $this->getUid(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if ($affectedRows === 1) {
|
||||
$table = $this->propertiesOfFileReference['tablenames'];
|
||||
$uidForeign = $this->propertiesOfFileReference['uid_foreign'];
|
||||
$referenceIndex = GeneralUtility::makeInstance(ReferenceIndex::class);
|
||||
$referenceIndex->updateRefIndexTable($table, $uidForeign);
|
||||
$referenceIndex->updateRefIndexTable('sys_file_reference', $this->getUid());
|
||||
}
|
||||
|
||||
return $affectedRows === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the fileName in this particular usage.
|
||||
*
|
||||
* @param non-empty-string $newName The new file name
|
||||
* @param DuplicationBehavior $conflictMode
|
||||
*/
|
||||
public function rename(string $newName, DuplicationBehavior $conflictMode = DuplicationBehavior::RENAME): FileInterface
|
||||
{
|
||||
// @todo Implement this function. This should only rename the
|
||||
// FileReference (sys_file_reference) record, not the file itself.
|
||||
throw new \BadMethodCallException('Function not implemented FileReference::rename().', 1333754473);
|
||||
//return $this->fileRepository->renameUsageRecord($this, $newName);
|
||||
}
|
||||
|
||||
/*****************
|
||||
* SPECIAL METHODS
|
||||
*****************/
|
||||
/**
|
||||
* Returns a publicly accessible URL for this file
|
||||
*
|
||||
* WARNING: Access to the file may be restricted by further means, e.g.
|
||||
* some web-based authentication. You have to take care of this yourself.
|
||||
*
|
||||
* @return non-empty-string|null NULL if file is missing or deleted, the generated url otherwise
|
||||
*/
|
||||
public function getPublicUrl(): ?string
|
||||
{
|
||||
return $this->originalFile->getPublicUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns TRUE if this file is indexed.
|
||||
* This is always true for FileReference objects, as they rely on a
|
||||
* sys_file_reference record to be present, which in turn can only exist if
|
||||
* the original file is indexed.
|
||||
*/
|
||||
public function isIndexed(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a path to a local version of this file to process it locally (e.g. with some system tool).
|
||||
* If the file is normally located on a remote storages, this creates a local copy.
|
||||
* If the file is already on the local system, this only makes a new copy if $writable is set to TRUE.
|
||||
*
|
||||
* @param bool $writable Set this to FALSE if you only want to do read operations on the file.
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getForLocalProcessing(bool $writable = true): string
|
||||
{
|
||||
return $this->originalFile->getForLocalProcessing($writable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the file.
|
||||
* (This is used by the generic listing module vidi when displaying file records.)
|
||||
*
|
||||
* @return array<non-empty-string, mixed> Array of main data of the file. Don't rely on all data to be present here, it's just a selection of the most relevant information.
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_merge($this->originalFile->toArray(), $this->propertiesOfFileReference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original file being referenced.
|
||||
*/
|
||||
public function getOriginalFile(): File
|
||||
{
|
||||
return $this->originalFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non-empty-string
|
||||
*/
|
||||
public function getHashedIdentifier(): string
|
||||
{
|
||||
return $this->getStorage()->hashFileIdentifier($this->getIdentifier());
|
||||
}
|
||||
|
||||
public function getParentFolder(): FolderInterface
|
||||
{
|
||||
return $this->originalFile->getParentFolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoids exporting original file object which contains
|
||||
* singleton dependencies that must not be serialized.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function __sleep(): array
|
||||
{
|
||||
$keys = get_object_vars($this);
|
||||
unset($keys['originalFile'], $keys['mergedProperties']);
|
||||
return array_keys($keys);
|
||||
}
|
||||
|
||||
public function __wakeup(): void
|
||||
{
|
||||
$factory = GeneralUtility::makeInstance(ResourceFactory::class);
|
||||
$this->originalFile = $this->getFileObject(
|
||||
(int)$this->propertiesOfFileReference['uid_local'],
|
||||
$factory
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?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\Resource;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Database\Connection;
|
||||
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
|
||||
use TYPO3\CMS\Core\Database\RelationHandler;
|
||||
use TYPO3\CMS\Core\Http\ApplicationType;
|
||||
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
|
||||
use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Repository for accessing file objects.
|
||||
* It also serves as the public API for the indexing part of files in general.
|
||||
*
|
||||
* It is however recommended to use the ResourceFactory instead of this class,
|
||||
* as it is more flexible.
|
||||
*/
|
||||
#[Autoconfigure(public: true)]
|
||||
readonly class FileRepository
|
||||
{
|
||||
public function __construct(
|
||||
protected ResourceFactory $factory,
|
||||
protected TcaSchemaFactory $tcaSchemaFactory,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Finds a File matching the given uid, regardless of the storage.
|
||||
*/
|
||||
public function findByUid(int $uid): File
|
||||
{
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_file');
|
||||
if ($this->isFrontend()) {
|
||||
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
|
||||
}
|
||||
$row = $queryBuilder
|
||||
->select('*')
|
||||
->from('sys_file')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, Connection::PARAM_INT))
|
||||
)
|
||||
->executeQuery()
|
||||
->fetchAssociative();
|
||||
if (!is_array($row)) {
|
||||
throw new \RuntimeException('Could not find row with UID "' . $uid . '" in table "sys_file"', 1314354065);
|
||||
}
|
||||
return $this->createDomainObject($row);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an object managed by this repository.
|
||||
*/
|
||||
protected function createDomainObject(array $databaseRow): File
|
||||
{
|
||||
return $this->factory->getFileObject((int)$databaseRow['uid'], $databaseRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find FileReference objects by relation to other records
|
||||
*
|
||||
* @param string $tableName Table name of the related record
|
||||
* @param string $fieldName Field name of the related record
|
||||
* @param int $uid The UID of the related record (needs to be the localized uid, as translated IRRE elements relate to them)
|
||||
* @param int|null $workspaceId
|
||||
* @return FileReference[] An array of file references, empty if no objects found
|
||||
*/
|
||||
public function findByRelation(string $tableName, string $fieldName, int $uid, ?int $workspaceId = null): array
|
||||
{
|
||||
$itemList = [];
|
||||
$referenceUids = [];
|
||||
if ($this->isFrontend()) {
|
||||
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
|
||||
->getQueryBuilderForTable('sys_file_reference');
|
||||
|
||||
$queryBuilder->setRestrictions(GeneralUtility::makeInstance(FrontendRestrictionContainer::class));
|
||||
$res = $queryBuilder
|
||||
->select('uid')
|
||||
->from('sys_file_reference')
|
||||
->where(
|
||||
$queryBuilder->expr()->eq(
|
||||
'uid_foreign',
|
||||
$queryBuilder->createNamedParameter($uid, Connection::PARAM_INT)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
'tablenames',
|
||||
$queryBuilder->createNamedParameter($tableName)
|
||||
),
|
||||
$queryBuilder->expr()->eq(
|
||||
'fieldname',
|
||||
$queryBuilder->createNamedParameter($fieldName)
|
||||
)
|
||||
)
|
||||
->orderBy('sorting_foreign')
|
||||
->executeQuery();
|
||||
|
||||
while ($row = $res->fetchAssociative()) {
|
||||
$referenceUids[] = $row['uid'];
|
||||
}
|
||||
} else {
|
||||
$schema = $this->tcaSchemaFactory->get($tableName);
|
||||
$workspaceId ??= GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('workspace', 'id', 0);
|
||||
$relationHandler = GeneralUtility::makeInstance(RelationHandler::class);
|
||||
$relationHandler->setWorkspaceId($workspaceId);
|
||||
$relationHandler->initializeForField(
|
||||
$tableName,
|
||||
$schema->getField($fieldName),
|
||||
$uid
|
||||
);
|
||||
if (!empty($relationHandler->tableArray['sys_file_reference'])) {
|
||||
$relationHandler->processDeletePlaceholder();
|
||||
$referenceUids = $relationHandler->tableArray['sys_file_reference'];
|
||||
}
|
||||
}
|
||||
if (!empty($referenceUids)) {
|
||||
foreach ($referenceUids as $referenceUid) {
|
||||
try {
|
||||
// Just passing the reference uid, the factory is doing workspace
|
||||
// overlays automatically depending on the current environment
|
||||
$itemList[] = $this->factory->getFileReferenceObject($referenceUid);
|
||||
} catch (ResourceDoesNotExistException) {
|
||||
// No handling, just omit the invalid reference uid
|
||||
}
|
||||
}
|
||||
$itemList = $this->reapplySorting($itemList);
|
||||
}
|
||||
|
||||
return $itemList;
|
||||
}
|
||||
|
||||
/**
|
||||
* As sorting might have changed due to workspace overlays, PHP does the sorting again.
|
||||
*
|
||||
* @param FileReference[] $itemList
|
||||
* @return FileReference[]
|
||||
*/
|
||||
protected function reapplySorting(array $itemList): array
|
||||
{
|
||||
uasort(
|
||||
$itemList,
|
||||
static function (FileReference $a, FileReference $b) {
|
||||
$sortA = (int)$a->getReferenceProperty('sorting_foreign');
|
||||
$sortB = (int)$b->getReferenceProperty('sorting_foreign');
|
||||
|
||||
if ($sortA === $sortB) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ($sortA < $sortB) ? -1 : 1;
|
||||
}
|
||||
);
|
||||
return $itemList;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function can be mocked in unit tests to be able to test frontend behaviour.
|
||||
*/
|
||||
protected function isFrontend(): bool
|
||||
{
|
||||
if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
|
||||
&& ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?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\Resource;
|
||||
|
||||
enum FileType: int
|
||||
{
|
||||
/**
|
||||
* any other file
|
||||
*/
|
||||
case UNKNOWN = 0;
|
||||
|
||||
/**
|
||||
* Any kind of text
|
||||
* @see http://www.iana.org/assignments/media-types/text
|
||||
*/
|
||||
case TEXT = 1;
|
||||
|
||||
/**
|
||||
* Any kind of image
|
||||
* @see http://www.iana.org/assignments/media-types/image
|
||||
*/
|
||||
case IMAGE = 2;
|
||||
|
||||
/**
|
||||
* Any kind of audio file
|
||||
* @see http://www.iana.org/assignments/media-types/audio
|
||||
*/
|
||||
case AUDIO = 3;
|
||||
|
||||
/**
|
||||
* Any kind of video
|
||||
* @see http://www.iana.org/assignments/media-types/video
|
||||
*/
|
||||
case VIDEO = 4;
|
||||
|
||||
/**
|
||||
* Any kind of application
|
||||
* @see http://www.iana.org/assignments/media-types/application
|
||||
*/
|
||||
case APPLICATION = 5;
|
||||
|
||||
public static function tryFromMimeType(string $mimeType): self
|
||||
{
|
||||
[$fileType] = explode('/', $mimeType);
|
||||
return match (strtolower($fileType)) {
|
||||
'text' => FileType::TEXT,
|
||||
'image' => FileType::IMAGE,
|
||||
'audio' => FileType::AUDIO,
|
||||
'video' => FileType::VIDEO,
|
||||
'application', 'software' => FileType::APPLICATION,
|
||||
default => FileType::UNKNOWN,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
<?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\Resource\Filter;
|
||||
|
||||
use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
|
||||
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
|
||||
use TYPO3\CMS\Core\Resource\ResourceFactory;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
|
||||
/**
|
||||
* Utility methods for filtering filenames
|
||||
*/
|
||||
class FileExtensionFilter
|
||||
{
|
||||
/**
|
||||
* Allowed file extensions. If NULL, all extensions are allowed.
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
protected ?array $allowedFileExtensions = null;
|
||||
|
||||
/**
|
||||
* Disallowed file extensions. If NULL, no extension is disallowed (i.e. all are allowed).
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
protected ?array $disallowedFileExtensions = null;
|
||||
|
||||
public function filter(array $references, string $allowedFileExtensions, string $disallowedFileExtensions): array
|
||||
{
|
||||
if ($allowedFileExtensions !== '') {
|
||||
$this->setAllowedFileExtensions($allowedFileExtensions);
|
||||
}
|
||||
if ($disallowedFileExtensions !== '') {
|
||||
$this->setDisallowedFileExtensions($disallowedFileExtensions);
|
||||
}
|
||||
$cleanReferences = [];
|
||||
foreach ($references as $reference) {
|
||||
if (empty($reference)) {
|
||||
continue;
|
||||
}
|
||||
$parts = GeneralUtility::revExplode('_', (string)$reference, 2);
|
||||
$fileReferenceUid = (int)$parts[count($parts) - 1];
|
||||
try {
|
||||
$fileReference = GeneralUtility::makeInstance(ResourceFactory::class)->getFileReferenceObject($fileReferenceUid);
|
||||
$file = $fileReference->getOriginalFile();
|
||||
if ($this->isAllowed($file->getExtension())) {
|
||||
$cleanReferences[] = $reference;
|
||||
}
|
||||
} catch (ResourceDoesNotExistException $e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
return $cleanReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry method for use as filelist filter.
|
||||
*
|
||||
* We use -1 as the "don't include“ return value, for historic reasons,
|
||||
* as call_user_func() used to return FALSE if calling the method failed.
|
||||
*
|
||||
* @param string $itemName
|
||||
* @param string $itemIdentifier
|
||||
* @param string $parentIdentifier
|
||||
* @param array $additionalInformation Additional information about the inspected item
|
||||
* @param DriverInterface $driver
|
||||
* @return bool|int -1 if the file should not be included in a listing
|
||||
*/
|
||||
public function filterFileList($itemName, $itemIdentifier, $parentIdentifier, array $additionalInformation, DriverInterface $driver)
|
||||
{
|
||||
$returnCode = true;
|
||||
// Early return in case no file filters are set at all
|
||||
if ($this->allowedFileExtensions === null && $this->disallowedFileExtensions === null) {
|
||||
return $returnCode;
|
||||
}
|
||||
// Check that this is a file and not a folder
|
||||
if ($driver->fileExists($itemIdentifier)) {
|
||||
try {
|
||||
$fileInfo = $driver->getFileInfoByIdentifier($itemIdentifier, ['extension']);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$fileInfo = [];
|
||||
}
|
||||
if (!$this->isAllowed((string)($fileInfo['extension'] ?? ''))) {
|
||||
$returnCode = -1;
|
||||
}
|
||||
}
|
||||
return $returnCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a file is allowed according to the criteria defined in the class variables ($this->allowedFileExtensions etc.)
|
||||
*
|
||||
* @internal this is used internally for TYPO3 core only
|
||||
*/
|
||||
public function isAllowed(string $fileExtension): bool
|
||||
{
|
||||
$fileExtension = strtolower($fileExtension);
|
||||
$result = true;
|
||||
// Check allowed file extensions
|
||||
if (!empty($this->allowedFileExtensions) && !in_array($fileExtension, $this->allowedFileExtensions, true)) {
|
||||
$result = false;
|
||||
}
|
||||
// Check disallowed file extensions
|
||||
if (!empty($this->disallowedFileExtensions) && in_array($fileExtension, $this->disallowedFileExtensions, true)) {
|
||||
$result = false;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set allowed file extensions
|
||||
*
|
||||
* @param mixed $allowedFileExtensions Comma-separated list or array, of allowed file extensions
|
||||
*/
|
||||
public function setAllowedFileExtensions(mixed $allowedFileExtensions): void
|
||||
{
|
||||
$this->allowedFileExtensions = $this->convertToLowercaseArray($allowedFileExtensions);
|
||||
}
|
||||
|
||||
public function getAllowedFileExtensions(): ?array
|
||||
{
|
||||
return $this->allowedFileExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set disallowed file extensions
|
||||
*
|
||||
* @param mixed $disallowedFileExtensions Comma-separated list or array, of allowed file extensions
|
||||
*/
|
||||
public function setDisallowedFileExtensions(mixed $disallowedFileExtensions): void
|
||||
{
|
||||
$this->disallowedFileExtensions = $this->convertToLowercaseArray($disallowedFileExtensions);
|
||||
}
|
||||
|
||||
public function getDisallowedFileExtensions(): ?array
|
||||
{
|
||||
return $this->disallowedFileExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compared the current allowed and disallowed lists and returns
|
||||
* a filtered list either as allow or as disallow list. The "mode"
|
||||
* is indicated by the array key, which is either "allowedFileExtensions"
|
||||
* or "disallowedFileExtensions".
|
||||
*/
|
||||
public function getFilteredFileExtensions(): array
|
||||
{
|
||||
if ($this->disallowedFileExtensions === null) {
|
||||
return ['allowedFileExtensions' => $this->allowedFileExtensions ?? ['*']];
|
||||
}
|
||||
|
||||
if ($this->allowedFileExtensions === null) {
|
||||
return ['disallowedFileExtensions' => $this->disallowedFileExtensions];
|
||||
}
|
||||
|
||||
return ['allowedFileExtensions' => array_filter($this->allowedFileExtensions, function (string $fileExtension): bool {
|
||||
return !in_array($fileExtension, $this->disallowedFileExtensions, true);
|
||||
})];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts mixed (string or array) input arguments into an array, NULL if empty.
|
||||
*
|
||||
* All array values will be converted to lower case.
|
||||
*/
|
||||
protected function convertToLowercaseArray(mixed $inputArgument): ?array
|
||||
{
|
||||
$returnValue = null;
|
||||
if (is_array($inputArgument)) {
|
||||
$returnValue = $inputArgument;
|
||||
} elseif ((string)$inputArgument !== '') {
|
||||
$returnValue = GeneralUtility::trimExplode(',', $inputArgument);
|
||||
}
|
||||
|
||||
if (is_array($returnValue)) {
|
||||
$returnValue = array_map(strtolower(...), $returnValue);
|
||||
}
|
||||
|
||||
return $returnValue;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user