TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
<?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\Backend\Tree;
|
||||
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
|
||||
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
|
||||
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderReadPermissionsException;
|
||||
use TYPO3\CMS\Core\Resource\Folder;
|
||||
use TYPO3\CMS\Core\Resource\FolderInterface;
|
||||
use TYPO3\CMS\Core\Resource\InaccessibleFolder;
|
||||
use TYPO3\CMS\Core\Resource\ResourceStorage;
|
||||
use TYPO3\CMS\Core\Resource\Utility\ListUtility;
|
||||
|
||||
/**
|
||||
* Responsible for fetching a tree-structure of folders.
|
||||
*
|
||||
* @internal not part of TYPO3 Core API due to the specific use case for the FileStorageTree component.
|
||||
*/
|
||||
readonly class FileStorageTreeProvider
|
||||
{
|
||||
public function prepareFolderInformation(Folder $folder, ?string $alternativeName = null, ?Folder $parentFolder = null, ?array $children = null): array
|
||||
{
|
||||
$name = $alternativeName ?? $folder->getName();
|
||||
$storage = $folder->getStorage();
|
||||
try {
|
||||
$parentFolder = $parentFolder ?? $folder->getParentFolder();
|
||||
} catch (InsufficientFolderAccessPermissionsException) {
|
||||
$parentFolder = null;
|
||||
}
|
||||
if (str_contains($folder->getRole(), FolderInterface::ROLE_MOUNT)) {
|
||||
$tableName = 'sys_filemount';
|
||||
$isStorage = true;
|
||||
} elseif ($parentFolder === null || $folder->getIdentifier() === $storage->getRootLevelFolder()->getIdentifier()) {
|
||||
$tableName = 'sys_file_storage';
|
||||
$isStorage = true;
|
||||
} else {
|
||||
$tableName = 'sys_file';
|
||||
$isStorage = false;
|
||||
}
|
||||
|
||||
try {
|
||||
$hasSubfolders = $storage->isBrowsable() && (is_array($children) ? $children !== [] : !empty($folder->getSubfolders()));
|
||||
} catch (\InvalidArgumentException|InsufficientFolderReadPermissionsException) {
|
||||
$hasSubfolders = false;
|
||||
}
|
||||
|
||||
return [
|
||||
'resource' => $folder,
|
||||
'identifier' => rawurlencode($folder->getCombinedIdentifier()),
|
||||
'name' => $name,
|
||||
'storage' => $storage->getUid(),
|
||||
'pathIdentifier' => rawurlencode($folder->getIdentifier()),
|
||||
'hasChildren' => $hasSubfolders,
|
||||
'parentIdentifier' => !$isStorage ? rawurlencode($parentFolder->getCombinedIdentifier()) : null,
|
||||
'recordType' => $tableName,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all file storages / file mounts visible for a user.
|
||||
*/
|
||||
public function getRootNodes(BackendUserAuthentication $user): array
|
||||
{
|
||||
$items = [];
|
||||
$storages = $user->getFileStorages();
|
||||
foreach ($storages as $storageObject) {
|
||||
$items = array_merge($items, $this->getFoldersInStorage($storageObject, $user));
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all folders recursively in a single store.
|
||||
*/
|
||||
protected function getFoldersInStorage(ResourceStorage $resourceStorage, BackendUserAuthentication $user): array
|
||||
{
|
||||
$rootLevelFolders = $this->getMountsInStorage($resourceStorage, $user);
|
||||
$items = [];
|
||||
foreach ($rootLevelFolders as $rootLevelFolderInfo) {
|
||||
/** @var Folder $rootLevelFolder */
|
||||
$rootLevelFolder = $rootLevelFolderInfo['folder'];
|
||||
$item = $this->prepareFolderInformation($rootLevelFolder, $rootLevelFolderInfo['name']);
|
||||
$item['depth'] = 0;
|
||||
$item['expanded'] = true;
|
||||
$item['loaded'] = true;
|
||||
$items[] = $item;
|
||||
if ($resourceStorage->isBrowsable()) {
|
||||
// Handle sub folders if the mount is browsable.
|
||||
$childItems = $this->getSubfolders($rootLevelFolder, 1);
|
||||
array_push($items, ...$childItems);
|
||||
}
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a tree by a search word
|
||||
*
|
||||
* @return FolderInterface[]
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getFilteredTree(BackendUserAuthentication $user, string $search): array
|
||||
{
|
||||
$foundFolders = [];
|
||||
$storages = $user->getFileStorages();
|
||||
foreach ($storages as $resourceStorage) {
|
||||
$processingFolders = $resourceStorage->getProcessingFolders();
|
||||
$processingFolderIdentifiers = array_map(static function (Folder $folder): string {
|
||||
return $folder->getIdentifier();
|
||||
}, $processingFolders);
|
||||
$resourceStorage->addFileAndFolderNameFilter(static function ($itemName, $itemIdentifier, $parentIdentifier, array $additionalInformation, DriverInterface $driver) use ($resourceStorage, $search, $processingFolderIdentifiers) {
|
||||
// Skip items in processing folders
|
||||
$isInProcessingFolder = array_filter($processingFolderIdentifiers, static function (string $processingFolderIdentifier) use ($parentIdentifier): bool {
|
||||
return stripos($parentIdentifier, $processingFolderIdentifier) !== false;
|
||||
});
|
||||
if (!empty($isInProcessingFolder)) {
|
||||
return -1;
|
||||
}
|
||||
if ($itemName instanceof Folder) {
|
||||
if ($resourceStorage->isProcessingFolder($itemName)) {
|
||||
return -1;
|
||||
}
|
||||
$name = $itemName->getName();
|
||||
} elseif (is_string($itemName)) {
|
||||
$name = $itemName;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
if (stripos($name, $search) !== false) {
|
||||
return true;
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
try {
|
||||
$files = $folders = [];
|
||||
// Because $resourceStorage->getRootLevelFolder() does not return an actual root folder but
|
||||
// the first file mount, we first need to check if we have file mounts and then fetch them one by one.
|
||||
if (($fileMounts = $resourceStorage->getFileMounts()) !== []) {
|
||||
foreach ($fileMounts as $identifier => $configuration) {
|
||||
foreach ($resourceStorage->getFilesInFolder($resourceStorage->getFolder($identifier), 0, 0, true, true) as $file) {
|
||||
$files[] = $file;
|
||||
}
|
||||
foreach ($resourceStorage->getFolderIdentifiersInFolder($identifier, true, true) as $folder) {
|
||||
$folders[] = $folder;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$files = $resourceStorage->getFilesInFolder($resourceStorage->getRootLevelFolder(), 0, 0, true, true);
|
||||
$folders = $resourceStorage->getFolderIdentifiersInFolder($resourceStorage->getRootLevelFolder()->getIdentifier(), true, true);
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
$folder = $file->getParentFolder();
|
||||
$foundFolders[$folder->getCombinedIdentifier()] = $folder;
|
||||
}
|
||||
foreach ($folders as $folder) {
|
||||
$folderObj = $resourceStorage->getFolder($folder);
|
||||
$foundFolders[$folderObj->getCombinedIdentifier()] = $folderObj;
|
||||
}
|
||||
} catch (InsufficientFolderAccessPermissionsException $e) {
|
||||
// do nothing
|
||||
}
|
||||
$resourceStorage->resetFileAndFolderNameFiltersToDefault();
|
||||
}
|
||||
return $foundFolders;
|
||||
}
|
||||
|
||||
public function getSubfolders(Folder $folderObject, int $currentDepth): array
|
||||
{
|
||||
$items = [];
|
||||
$subFolders = [];
|
||||
if (!$folderObject instanceof InaccessibleFolder) {
|
||||
$subFolders = $folderObject->getSubfolders();
|
||||
$subFolders = ListUtility::resolveSpecialFolderNames($subFolders);
|
||||
uksort($subFolders, strnatcasecmp(...));
|
||||
}
|
||||
foreach ($subFolders as $subFolderName => $subFolder) {
|
||||
$subFolderName = (string)$subFolderName; // Enforce string cast in case $subFolderName contains numeric chars only
|
||||
$children = [];
|
||||
if (!($subFolder instanceof InaccessibleFolder)) {
|
||||
// Get children to determine if that folder can be expanded again, 'hasChildren true' then renders expand triangle
|
||||
$children = $subFolder->getSubfolders();
|
||||
}
|
||||
$items[] = array_merge(
|
||||
$this->prepareFolderInformation($subFolder, $subFolderName, $folderObject, $children),
|
||||
[
|
||||
'depth' => $currentDepth,
|
||||
'expanded' => false,
|
||||
'loaded' => false,
|
||||
]
|
||||
);
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all "root level folders" of a storage. If a user has file mounts in this storage, they are properly resolved.
|
||||
*
|
||||
* @return array|array[]
|
||||
*/
|
||||
protected function getMountsInStorage(ResourceStorage $resourceStorage, BackendUserAuthentication $user): array
|
||||
{
|
||||
$fileMounts = $resourceStorage->getFileMounts();
|
||||
if (!empty($fileMounts)) {
|
||||
return array_map(static function (array $fileMountInfo): array {
|
||||
return [
|
||||
'folder' => $fileMountInfo['folder'],
|
||||
'name' => $fileMountInfo['title'],
|
||||
];
|
||||
}, $fileMounts);
|
||||
}
|
||||
|
||||
if ($user->isAdmin()) {
|
||||
return [
|
||||
[
|
||||
'folder' => $resourceStorage->getRootLevelFolder(),
|
||||
'name' => $resourceStorage->getName(),
|
||||
],
|
||||
];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user