‪TYPO3CMS  ‪main
FileStorageTreeProvider.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
22 use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
32 
39 {
40  protected ?array ‪$expandedState = null;
41  protected string ‪$userSettingsIdentifier = 'BackendComponents.States.FileStorageTree';
42 
43  public function ‪prepareFolderInformation(‪Folder $folder, ?string $alternativeName = null, ?‪Folder $parentFolder = null, ?array $children = null): array
44  {
45  $name = $alternativeName ?? $folder->‪getName();
46  $storage = $folder->‪getStorage();
47  try {
48  $parentFolder = $parentFolder ?? $folder->‪getParentFolder();
50  $parentFolder = null;
51  }
52  if (str_contains($folder->‪getRole(), ‪FolderInterface::ROLE_MOUNT)) {
53  $tableName = 'sys_filemount';
54  $isStorage = true;
55  } elseif ($parentFolder === null || $folder->‪getIdentifier() === $storage->getRootLevelFolder(true)->getIdentifier()) {
56  $tableName = 'sys_file_storage';
57  $isStorage = true;
58  } else {
59  $tableName = 'sys_file';
60  $isStorage = false;
61  }
62 
63  try {
64  $hasSubfolders = is_array($children) ? $children !== [] : !empty($folder->‪getSubfolders());
65  } catch (\InvalidArgumentException | ‪InsufficientFolderReadPermissionsException $e) {
66  $hasSubfolders = false;
67  }
68 
69  return [
70  'resource' => $folder,
71  'identifier' => rawurlencode($folder->‪getCombinedIdentifier()),
72  'name' => $name,
73  'storage' => $storage->getUid(),
74  'pathIdentifier' => rawurlencode($folder->‪getIdentifier()),
75  'hasChildren' => $hasSubfolders,
76  'parentIdentifier' => $parentFolder instanceof ‪Folder && !$isStorage ? rawurlencode($parentFolder->getCombinedIdentifier()) : null,
77  'recordType' => $tableName,
78  ];
79  }
80 
84  public function ‪getRootNodes(‪BackendUserAuthentication $user): array
85  {
86  $items = [];
87  $storages = $user->‪getFileStorages();
88  foreach ($storages as $storageObject) {
89  $items = array_merge($items, $this->‪getFoldersInStorage($storageObject, $user));
90  }
91  return $items;
92  }
93 
97  protected function ‪getFoldersInStorage(‪ResourceStorage $resourceStorage, ‪BackendUserAuthentication $user): array
98  {
99  $rootLevelFolders = $this->‪getMountsInStorage($resourceStorage, $user);
100  $items = [];
101  foreach ($rootLevelFolders as $i => $rootLevelFolderInfo) {
103  $rootLevelFolder = $rootLevelFolderInfo['folder'];
104  // Root level is always expanded if not defined otherwise
105  $expanded = $this->‪isExpanded($rootLevelFolder, true);
106 
107  $itm = $this->‪prepareFolderInformation($rootLevelFolder, $rootLevelFolderInfo['name']);
108  $itm['depth'] = 0;
109  $itm['expanded'] = $expanded;
110  $itm['loaded'] = $expanded;
111  $items[] = $itm;
112 
113  // If the mount is expanded, go down:
114  if ($expanded && $resourceStorage->‪isBrowsable()) {
115  $childItems = $this->‪getSubfoldersRecursively($rootLevelFolder, 1);
116  array_push($items, ...$childItems);
117  }
118  }
119  return $items;
120  }
121 
128  public function ‪getFilteredTree(‪BackendUserAuthentication $user, string $search): array
129  {
130  $foundFolders = [];
131  $storages = $user->‪getFileStorages();
132  foreach ($storages as $resourceStorage) {
133  $processingFolders = $resourceStorage->getProcessingFolders();
134  $processingFolderIdentifiers = array_map(static function (‪Folder $folder): string {
135  return $folder->‪getIdentifier();
136  }, $processingFolders);
137  $resourceStorage->addFileAndFolderNameFilter(static function ($itemName, $itemIdentifier, $parentIdentifier, array $additionalInformation, DriverInterface $driver) use ($resourceStorage, $search, $processingFolderIdentifiers) {
138  // Skip items in processing folders
139  $isInProcessingFolder = array_filter($processingFolderIdentifiers, static function (string $processingFolderIdentifier) use ($parentIdentifier): bool {
140  return stripos($parentIdentifier, $processingFolderIdentifier) !== false;
141  });
142  if (!empty($isInProcessingFolder)) {
143  return -1;
144  }
145  if ($itemName instanceof ‪Folder) {
146  if ($resourceStorage->isProcessingFolder($itemName)) {
147  return -1;
148  }
149  $name = $itemName->getName();
150  } elseif (is_string($itemName)) {
151  $name = $itemName;
152  } else {
153  return -1;
154  }
155  if (stripos($name, $search) !== false) {
156  return true;
157  }
158  return -1;
159  });
160  try {
161  $files = $folders = [];
162  // Because $resourceStorage->getRootLevelFolder() does not return an actual root folder but
163  // the first file mount, we first need to check if we have file mounts and then fetch them one by one.
164  if (($fileMounts = $resourceStorage->getFileMounts()) !== []) {
165  foreach ($fileMounts as ‪$identifier => $configuration) {
166  foreach ($resourceStorage->getFilesInFolder($resourceStorage->getFolder(‪$identifier), 0, 0, true, true) as $file) {
167  $files[] = $file;
168  }
169  foreach ($resourceStorage->getFolderIdentifiersInFolder(‪$identifier, true, true) as $folder) {
170  $folders[] = $folder;
171  }
172  }
173  } else {
174  $files = $resourceStorage->getFilesInFolder($resourceStorage->getRootLevelFolder(), 0, 0, true, true);
175  $folders = $resourceStorage->getFolderIdentifiersInFolder($resourceStorage->getRootLevelFolder()->getIdentifier(), true, true);
176  }
177  foreach ($files as $file) {
178  $folder = $file->‪getParentFolder();
179  $foundFolders[$folder->‪getCombinedIdentifier()] = $folder;
180  }
181  foreach ($folders as $folder) {
182  $folderObj = $resourceStorage->getFolder($folder);
183  if ($folderObj !== null) {
184  $foundFolders[$folderObj->getCombinedIdentifier()] = $folderObj;
185  }
186  }
188  // do nothing
189  }
190  $resourceStorage->resetFileAndFolderNameFiltersToDefault();
191  }
192  return $foundFolders;
193  }
194 
195  public function ‪getSubfoldersRecursively(‪Folder $folderObject, int $currentDepth, ?array $subFolders = null): array
196  {
197  $items = [];
198  if ($folderObject instanceof ‪InaccessibleFolder) {
199  $subFolders = [];
200  } else {
201  $subFolders = is_array($subFolders) ? $subFolders : $folderObject->‪getSubfolders();
202  $subFolders = ListUtility::resolveSpecialFolderNames($subFolders);
203  uksort($subFolders, strnatcasecmp(...));
204  }
205 
206  foreach ($subFolders as $subFolderName => $subFolder) {
207  $subFolderName = (string)$subFolderName; // Enforce string cast in case $subFolderName contains numeric chars only
208  $expanded = $this->‪isExpanded($subFolder);
209  if (!($subFolder instanceof ‪InaccessibleFolder)) {
210  $children = $subFolder->getSubfolders();
211  } else {
212  $children = [];
213  }
214 
215  $items[] = array_merge(
216  $this->‪prepareFolderInformation($subFolder, $subFolderName, $folderObject, $children),
217  [
218  'depth' => $currentDepth,
219  'expanded' => $expanded,
220  'loaded' => $expanded,
221  ]
222  );
223 
224  if ($expanded && !empty($children)) {
225  $childItems = $this->‪getSubfoldersRecursively($subFolder, $currentDepth + 1, $children);
226  array_push($items, ...$childItems);
227  }
228  }
229  return $items;
230  }
231 
237  protected function ‪getMountsInStorage(‪ResourceStorage $resourceStorage, ‪BackendUserAuthentication $user): array
238  {
239  $fileMounts = $resourceStorage->‪getFileMounts();
240  if (!empty($fileMounts)) {
241  return array_map(static function (array $fileMountInfo): array {
242  return [
243  'folder' => $fileMountInfo['folder'],
244  'name' => $fileMountInfo['title'],
245  ];
246  }, $fileMounts);
247  }
248 
249  if ($user->‪isAdmin()) {
250  return [
251  [
252  'folder' => $resourceStorage->‪getRootLevelFolder(),
253  'name' => $resourceStorage->‪getName(),
254  ],
255  ];
256  }
257  return [];
258  }
259 
263  protected function ‪isExpanded(‪Folder $folder, bool $fallback = false): bool
264  {
265  if (!is_array($this->expandedState)) {
266  $this->expandedState = GeneralUtility::makeInstance(BackendUserConfiguration::class)->get($this->userSettingsIdentifier);
267  $this->expandedState = ($this->expandedState['stateHash'] ?? []) ?: [];
268  }
269  return (bool)($this->expandedState[$folder->‪getIdentifier()] ?? $fallback);
270  }
271 }
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider\getMountsInStorage
‪array array[] getMountsInStorage(ResourceStorage $resourceStorage, BackendUserAuthentication $user)
Definition: FileStorageTreeProvider.php:237
‪TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException
Definition: InsufficientFolderAccessPermissionsException.php:23
‪TYPO3\CMS\Core\Resource\ResourceStorage\getRootLevelFolder
‪getRootLevelFolder(bool $respectFileMounts=true)
Definition: ResourceStorage.php:2649
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider\isExpanded
‪isExpanded(Folder $folder, bool $fallback=false)
Definition: FileStorageTreeProvider.php:263
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider\$expandedState
‪array $expandedState
Definition: FileStorageTreeProvider.php:40
‪TYPO3\CMS\Core\Resource\Folder\getSubfolders
‪getSubfolders($start=0, $numberOfItems=0, $filterMode=self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, $recursive=false)
Definition: Folder.php:267
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\isAdmin
‪bool isAdmin()
Definition: BackendUserAuthentication.php:241
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider\getSubfoldersRecursively
‪getSubfoldersRecursively(Folder $folderObject, int $currentDepth, ?array $subFolders=null)
Definition: FileStorageTreeProvider.php:195
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider
Definition: FileStorageTreeProvider.php:39
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider\getFilteredTree
‪FolderInterface[] getFilteredTree(BackendUserAuthentication $user, string $search)
Definition: FileStorageTreeProvider.php:128
‪TYPO3\CMS\Backend\Tree
Definition: AbstractTree.php:16
‪TYPO3\CMS\Core\Resource\Utility\ListUtility
Definition: ListUtility.php:26
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication\getFileStorages
‪TYPO3 CMS Core Resource ResourceStorage[] getFileStorages()
Definition: BackendUserAuthentication.php:1368
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider\getRootNodes
‪getRootNodes(BackendUserAuthentication $user)
Definition: FileStorageTreeProvider.php:84
‪TYPO3\CMS\Core\Resource\Folder\getParentFolder
‪getParentFolder()
Definition: Folder.php:553
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider\getFoldersInStorage
‪getFoldersInStorage(ResourceStorage $resourceStorage, BackendUserAuthentication $user)
Definition: FileStorageTreeProvider.php:97
‪TYPO3\CMS\Core\Resource\InaccessibleFolder
Definition: InaccessibleFolder.php:30
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider\prepareFolderInformation
‪prepareFolderInformation(Folder $folder, ?string $alternativeName=null, ?Folder $parentFolder=null, ?array $children=null)
Definition: FileStorageTreeProvider.php:43
‪TYPO3\CMS\Backend\Tree\FileStorageTreeProvider\$userSettingsIdentifier
‪string $userSettingsIdentifier
Definition: FileStorageTreeProvider.php:41
‪TYPO3\CMS\Backend\Configuration\BackendUserConfiguration
Definition: BackendUserConfiguration.php:30
‪TYPO3\CMS\Core\Resource\ResourceStorage\isBrowsable
‪bool isBrowsable()
Definition: ResourceStorage.php:414
‪TYPO3\CMS\Core\Resource\Folder
Definition: Folder.php:38
‪TYPO3\CMS\Core\Resource\Exception\FolderDoesNotExistException
Definition: FolderDoesNotExistException.php:21
‪TYPO3\CMS\Core\Resource\Folder\getStorage
‪getStorage()
Definition: Folder.php:139
‪TYPO3\CMS\Core\Authentication\BackendUserAuthentication
Definition: BackendUserAuthentication.php:62
‪TYPO3\CMS\Core\Resource\Folder\getName
‪getName()
Definition: Folder.php:89
‪TYPO3\CMS\Core\Resource\ResourceStorage\getFileMounts
‪array getFileMounts()
Definition: ResourceStorage.php:595
‪TYPO3\CMS\Core\Resource\Folder\getRole
‪string getRole()
Definition: Folder.php:539
‪TYPO3\CMS\Core\Resource\FolderInterface\ROLE_MOUNT
‪const ROLE_MOUNT
Definition: FolderInterface.php:33
‪TYPO3\CMS\Core\Resource\ResourceStorage
Definition: ResourceStorage.php:129
‪TYPO3\CMS\Core\Resource\FolderInterface
Definition: FolderInterface.php:24
‪TYPO3\CMS\Core\Resource\Folder\getIdentifier
‪non empty string getIdentifier()
Definition: Folder.php:150
‪TYPO3\CMS\Core\Resource\Folder\getCombinedIdentifier
‪string getCombinedIdentifier()
Definition: Folder.php:166
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Webhooks\Message\$identifier
‪identifier readonly string $identifier
Definition: FileAddedMessage.php:37
‪TYPO3\CMS\Core\Resource\ResourceStorage\getName
‪string getName()
Definition: ResourceStorage.php:328
‪TYPO3\CMS\Core\Resource\Exception\InsufficientFolderReadPermissionsException
Definition: InsufficientFolderReadPermissionsException.php:21