1
|
|
|
<?php |
2
|
|
|
namespace Fab\Media\Module; |
3
|
|
|
|
4
|
|
|
/* |
5
|
|
|
* This file is part of the Fab/Media project under GPLv2 or later. |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please read the |
8
|
|
|
* LICENSE.md file that was distributed with this source code. |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
use Fab\Media\FileUpload\UploadedFileInterface; |
12
|
|
|
use Fab\Media\Utility\SessionUtility; |
13
|
|
|
use Fab\Vidi\Service\DataService; |
14
|
|
|
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration; |
15
|
|
|
use TYPO3\CMS\Core\Resource\File; |
16
|
|
|
use TYPO3\CMS\Core\Resource\Folder; |
17
|
|
|
use TYPO3\CMS\Core\Resource\ResourceFactory; |
18
|
|
|
use TYPO3\CMS\Core\Resource\ResourceStorage; |
19
|
|
|
use TYPO3\CMS\Core\Resource\StorageRepository; |
20
|
|
|
use TYPO3\CMS\Core\SingletonInterface; |
21
|
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Class for retrieving information about the Media module. |
25
|
|
|
*/ |
26
|
|
|
class MediaModule implements SingletonInterface |
27
|
|
|
{ |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @var string |
31
|
|
|
*/ |
32
|
|
|
const SIGNATURE = 'user_MediaM1'; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @var string |
36
|
|
|
*/ |
37
|
|
|
const PARAMETER_PREFIX = 'tx_media_user_mediam1'; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* @var ResourceStorage |
41
|
|
|
*/ |
42
|
|
|
protected $currentStorage; |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @return string |
46
|
|
|
*/ |
47
|
|
|
static public function getSignature() |
48
|
|
|
{ |
49
|
|
|
return self::SIGNATURE; |
50
|
|
|
} |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @return string |
54
|
|
|
*/ |
55
|
|
|
static public function getParameterPrefix() |
56
|
|
|
{ |
57
|
|
|
return self::PARAMETER_PREFIX; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Return all storage allowed for the Backend User. |
62
|
|
|
* |
63
|
|
|
* @throws \RuntimeException |
64
|
|
|
* @return ResourceStorage[] |
65
|
|
|
*/ |
66
|
|
|
public function getAllowedStorages() |
67
|
|
|
{ |
68
|
|
|
|
69
|
|
|
$storages = $this->getBackendUser()->getFileStorages(); |
70
|
|
|
if (empty($storages)) { |
71
|
|
|
throw new \RuntimeException('No storage is accessible for the current BE User. Forgotten to define a mount point for this BE User?', 1380801970); |
72
|
|
|
} |
73
|
|
|
return $storages; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Returns the current file storage in use. |
78
|
|
|
* |
79
|
|
|
* @return ResourceStorage |
80
|
|
|
*/ |
81
|
|
|
public function getCurrentStorage() |
82
|
|
|
{ |
83
|
|
|
if (is_null($this->currentStorage)) { |
84
|
|
|
|
85
|
|
|
$storageIdentifier = $this->getStorageIdentifierFromSessionOrArguments(); |
86
|
|
|
|
87
|
|
|
if ($storageIdentifier > 0) { |
88
|
|
|
$currentStorage = ResourceFactory::getInstance()->getStorageObject($storageIdentifier); |
89
|
|
|
} else { |
90
|
|
|
|
91
|
|
|
// We differentiate the cases whether the User is admin or not. |
92
|
|
|
if ($this->getBackendUser()->isAdmin()) { |
93
|
|
|
|
94
|
|
|
$currentStorage = ResourceFactory::getInstance()->getDefaultStorage(); |
95
|
|
|
|
96
|
|
|
// Not default storage has been flagged in "sys_file_storage". |
97
|
|
|
// Fallback approach: take the first storage as the current. |
98
|
|
|
if (!$currentStorage) { |
99
|
|
|
/** @var $storageRepository StorageRepository */ |
100
|
|
|
$storageRepository = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\StorageRepository::class); |
101
|
|
|
|
102
|
|
|
$storages = $storageRepository->findAll(); |
103
|
|
|
$currentStorage = current($storages); |
104
|
|
|
} |
105
|
|
|
} else { |
106
|
|
|
$fileMounts = $this->getBackendUser()->getFileMountRecords(); |
107
|
|
|
$firstFileMount = current($fileMounts); |
108
|
|
|
$currentStorage = ResourceFactory::getInstance()->getStorageObject($firstFileMount['base']); |
109
|
|
|
} |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
$this->currentStorage = $currentStorage; |
113
|
|
|
} |
114
|
|
|
return $this->currentStorage; |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Retrieve a possible storage identifier from the session or from the arguments. |
119
|
|
|
* |
120
|
|
|
* @return int |
121
|
|
|
*/ |
122
|
|
|
protected function getStorageIdentifierFromSessionOrArguments() |
123
|
|
|
{ |
124
|
|
|
|
125
|
|
|
// Default value |
126
|
|
|
$storageIdentifier = 0; |
127
|
|
|
|
128
|
|
|
// Get last selected storage from User settings |
129
|
|
|
if (SessionUtility::getInstance()->get('lastSelectedStorage') > 0) { |
130
|
|
|
$storageIdentifier = SessionUtility::getInstance()->get('lastSelectedStorage'); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
$argumentPrefix = $this->getModuleLoader()->getParameterPrefix(); |
134
|
|
|
$arguments = GeneralUtility::_GET($argumentPrefix); |
135
|
|
|
|
136
|
|
|
// Override selected storage from the session if GET argument "storage" is detected. |
137
|
|
|
if (!empty($arguments['storage']) && (int)$arguments['storage'] > 0) { |
138
|
|
|
$storageIdentifier = (int)$arguments['storage']; |
139
|
|
|
|
140
|
|
|
// Save state |
141
|
|
|
SessionUtility::getInstance()->set('lastSelectedStorage', $storageIdentifier); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
return (int)$storageIdentifier; |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* Return the combined parameter from the URL. |
149
|
|
|
* |
150
|
|
|
* @return string |
151
|
|
|
*/ |
152
|
|
|
public function getCombinedIdentifier() |
153
|
|
|
{ |
154
|
|
|
|
155
|
|
|
// Fetch possible combined identifier. |
156
|
|
|
$combinedIdentifier = GeneralUtility::_GET('id'); |
157
|
|
|
|
158
|
|
|
if ($combinedIdentifier) { |
159
|
|
|
|
160
|
|
|
// Fix a bug at the Core level: the "id" parameter is encoded again when translating file. |
161
|
|
|
// Add a loop to decode maximum 999 time! |
162
|
|
|
$semaphore = 0; |
163
|
|
|
$semaphoreLimit = 999; |
164
|
|
|
while (!$this->isWellDecoded($combinedIdentifier) && $semaphore < $semaphoreLimit) { |
165
|
|
|
$combinedIdentifier = urldecode($combinedIdentifier); |
166
|
|
|
$semaphore++; |
167
|
|
|
} |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
return $combinedIdentifier; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* @param $combinedIdentifier |
175
|
|
|
* @return bool |
176
|
|
|
*/ |
177
|
|
|
protected function isWellDecoded($combinedIdentifier) |
178
|
|
|
{ |
179
|
|
|
return preg_match('/.*:.*/', $combinedIdentifier); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* @return Folder |
184
|
|
|
*/ |
185
|
|
|
public function getFirstAvailableFolder() |
186
|
|
|
{ |
187
|
|
|
|
188
|
|
|
// Take the first object of the first storage. |
189
|
|
|
$storages = $this->getBackendUser()->getFileStorages(); |
190
|
|
|
$storage = reset($storages); |
191
|
|
|
if ($storage) { |
192
|
|
|
$folder = $storage->getRootLevelFolder(); |
193
|
|
|
} else { |
194
|
|
|
throw new \RuntimeException('Could not find any folder to be displayed.', 1444665954); |
195
|
|
|
} |
196
|
|
|
return $folder; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* @return Folder |
201
|
|
|
*/ |
202
|
|
|
public function getCurrentFolder() |
203
|
|
|
{ |
204
|
|
|
|
205
|
|
|
$combinedIdentifier = $this->getCombinedIdentifier(); |
206
|
|
|
|
207
|
|
|
if ($combinedIdentifier) { |
208
|
|
|
$folder = $this->getFolderForCombinedIdentifier($combinedIdentifier); |
209
|
|
|
} else { |
210
|
|
|
$folder = $this->getFirstAvailableFolder(); |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
return $folder; |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* @param string $combinedIdentifier |
218
|
|
|
* @return Folder |
219
|
|
|
*/ |
220
|
|
|
public function getFolderForCombinedIdentifier($combinedIdentifier) |
221
|
|
|
{ |
222
|
|
|
|
223
|
|
|
// Code taken from FileListController.php |
224
|
|
|
$storage = ResourceFactory::getInstance()->getStorageObjectFromCombinedIdentifier($combinedIdentifier); |
225
|
|
|
$identifier = substr($combinedIdentifier, strpos($combinedIdentifier, ':') + 1); |
226
|
|
|
if (!$storage->hasFolder($identifier)) { |
227
|
|
|
$identifier = $storage->getFolderIdentifierFromFileIdentifier($identifier); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
// Retrieve the folder object. |
231
|
|
|
$folder = ResourceFactory::getInstance()->getFolderObjectFromCombinedIdentifier($storage->getUid() . ':' . $identifier); |
232
|
|
|
|
233
|
|
|
// Disallow the rendering of the processing folder (e.g. could be called manually) |
234
|
|
|
// and all folders without any defined storage |
235
|
|
|
if ($folder && ($folder->getStorage()->getUid() == 0 || trim($folder->getStorage()->getProcessingFolder()->getIdentifier(), '/') === trim($folder->getIdentifier(), '/'))) { |
236
|
|
|
$storage = ResourceFactory::getInstance()->getStorageObjectFromCombinedIdentifier($combinedIdentifier); |
237
|
|
|
$folder = $storage->getRootLevelFolder(); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
return $folder; |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Tell whether the Folder Tree is display or not. |
245
|
|
|
* |
246
|
|
|
* @return bool |
247
|
|
|
*/ |
248
|
|
|
public function hasFolderTree() |
249
|
|
|
{ |
250
|
|
|
$configuration = $this->getModuleConfiguration(); |
251
|
|
|
return (bool)$configuration['has_folder_tree']; |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Tell whether the sub-folders must be included when browsing. |
256
|
|
|
* |
257
|
|
|
* @return bool |
258
|
|
|
*/ |
259
|
|
|
public function hasRecursiveSelection() |
260
|
|
|
{ |
261
|
|
|
|
262
|
|
|
$parameterPrefix = $this->getModuleLoader()->getParameterPrefix(); |
263
|
|
|
$parameters = GeneralUtility::_GET($parameterPrefix); |
264
|
|
|
|
265
|
|
|
$hasRecursiveSelection = true; |
266
|
|
|
if (isset($parameters['hasRecursiveSelection'])) { |
267
|
|
|
$hasRecursiveSelection = (bool)$parameters['hasRecursiveSelection']; |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
return $hasRecursiveSelection; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* Return the target folder for the uploaded file. |
275
|
|
|
* |
276
|
|
|
* @param UploadedFileInterface $uploadedFile |
277
|
|
|
* @param ResourceStorage $storage |
278
|
|
|
* @return \TYPO3\CMS\Core\Resource\Folder |
279
|
|
|
*/ |
280
|
|
View Code Duplication |
public function getTargetFolderForUploadedFile(UploadedFileInterface $uploadedFile, ResourceStorage $storage) |
|
|
|
|
281
|
|
|
{ |
282
|
|
|
|
283
|
|
|
// default is the root level |
284
|
|
|
$folder = $storage->getRootLevelFolder(); // get the root folder by default |
285
|
|
|
|
286
|
|
|
// Get a possible mount point coming from the storage record. |
287
|
|
|
$storageRecord = $storage->getStorageRecord(); |
288
|
|
|
$mountPointIdentifier = $storageRecord['mount_point_file_type_' . $uploadedFile->getType()]; |
289
|
|
|
if ($mountPointIdentifier > 0) { |
290
|
|
|
|
291
|
|
|
// We don't have a Mount Point repository in FAL, so query the database directly. |
292
|
|
|
$record = $this->getDataService()->getRecord('sys_filemounts', ['uid' => $mountPointIdentifier]); |
293
|
|
|
|
294
|
|
|
if (!empty($record['path'])) { |
295
|
|
|
$folder = $storage->getFolder($record['path']); |
296
|
|
|
} |
297
|
|
|
} |
298
|
|
|
return $folder; |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Return a new target folder when moving file from one storage to another. |
303
|
|
|
* |
304
|
|
|
* @param ResourceStorage $storage |
305
|
|
|
* @param File $file |
306
|
|
|
* @return \TYPO3\CMS\Core\Resource\Folder |
307
|
|
|
*/ |
308
|
|
View Code Duplication |
public function getDefaultFolderInStorage(ResourceStorage $storage, File $file) |
|
|
|
|
309
|
|
|
{ |
310
|
|
|
|
311
|
|
|
// default is the root level |
312
|
|
|
$folder = $storage->getRootLevelFolder(); |
313
|
|
|
|
314
|
|
|
// Retrieve storage record and a possible configured mount point. |
315
|
|
|
$storageRecord = $storage->getStorageRecord(); |
316
|
|
|
$mountPointIdentifier = $storageRecord['mount_point_file_type_' . $file->getType()]; |
317
|
|
|
|
318
|
|
|
if ($mountPointIdentifier > 0) { |
319
|
|
|
|
320
|
|
|
// We don't have a Mount Point repository in FAL, so query the database directly. |
321
|
|
|
$record = $this->getDataService()->getRecord('sys_filemounts', ['uid' => $mountPointIdentifier]); |
322
|
|
|
if (!empty($record['path'])) { |
323
|
|
|
$folder = $storage->getFolder($record['path']); |
324
|
|
|
} |
325
|
|
|
} |
326
|
|
|
return $folder; |
327
|
|
|
} |
328
|
|
|
|
329
|
|
|
/** |
330
|
|
|
* @return array |
331
|
|
|
*/ |
332
|
|
|
protected function getModuleConfiguration() |
333
|
|
|
{ |
334
|
|
|
return GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('media'); |
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
/** |
338
|
|
|
* @return object|DataService |
339
|
|
|
*/ |
340
|
|
|
protected function getDataService(): DataService |
341
|
|
|
{ |
342
|
|
|
return GeneralUtility::makeInstance(DataService::class); |
343
|
|
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Returns an instance of the current Backend User. |
347
|
|
|
* |
348
|
|
|
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication |
349
|
|
|
*/ |
350
|
|
|
protected function getBackendUser() |
351
|
|
|
{ |
352
|
|
|
return $GLOBALS['BE_USER']; |
353
|
|
|
} |
354
|
|
|
|
355
|
|
|
/** |
356
|
|
|
* Return the module loader. |
357
|
|
|
* |
358
|
|
|
* @return \Fab\Vidi\Module\ModuleLoader|object |
359
|
|
|
*/ |
360
|
|
|
protected function getModuleLoader() |
361
|
|
|
{ |
362
|
|
|
return GeneralUtility::makeInstance(\Fab\Vidi\Module\ModuleLoader::class); |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
} |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.