[TASK] Only show active packages in PackageStates.php
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / Folder.php
1 <?php
2 namespace TYPO3\CMS\Core\Resource;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\PathUtility;
18
19 /**
20 * A folder that groups files in a storage. This may be a folder on the local
21 * disk, a bucket in Amazon S3 or a user or a tag in Flickr.
22 *
23 * This object is not persisted in TYPO3 locally, but created on the fly by
24 * storage drivers for the folders they "offer".
25 *
26 * Some folders serve as a physical container for files (e.g. folders on the
27 * local disk, S3 buckets or Flickr users). Other folders just group files by a
28 * certain criterion, e.g. a tag.
29 * The way this is implemented depends on the storage driver.
30 */
31 class Folder implements FolderInterface
32 {
33 /**
34 * The storage this folder belongs to.
35 *
36 * @var ResourceStorage
37 */
38 protected $storage;
39
40 /**
41 * The identifier of this folder to identify it on the storage.
42 * On some drivers, this is the path to the folder, but drivers could also just
43 * provide any other unique identifier for this folder on the specific storage.
44 *
45 * @var string
46 */
47 protected $identifier;
48
49 /**
50 * The name of this folder
51 *
52 * @var string
53 */
54 protected $name;
55
56 /**
57 * The filters this folder should use for a filelist.
58 *
59 * @var callable[]
60 */
61 protected $fileAndFolderNameFilters = array();
62
63 /**
64 * Modes for filter usage in getFiles()/getFolders()
65 */
66 const FILTER_MODE_NO_FILTERS = 0;
67 // Merge local filters into storage's filters
68 const FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS = 1;
69 // Only use the filters provided by the storage
70 const FILTER_MODE_USE_STORAGE_FILTERS = 2;
71 // Only use the filters provided by the current class
72 const FILTER_MODE_USE_OWN_FILTERS = 3;
73
74 /**
75 * Initialization of the folder
76 *
77 * @param ResourceStorage $storage
78 * @param $identifier
79 * @param $name
80 */
81 public function __construct(ResourceStorage $storage, $identifier, $name)
82 {
83 $this->storage = $storage;
84 $this->identifier = $identifier;
85 $this->name = $name;
86 }
87
88 /**
89 * Returns the name of this folder.
90 *
91 * @return string
92 */
93 public function getName()
94 {
95 return $this->name;
96 }
97
98 /**
99 * Returns the full path of this folder, from the root.
100 *
101 * @param string $rootId ID of the root folder, NULL to auto-detect
102 *
103 * @return string
104 */
105 public function getReadablePath($rootId = null)
106 {
107 if ($rootId === null) {
108 $rootId = $this->storage->getRootLevelFolder()->getIdentifier();
109 }
110 $readablePath = '/';
111 if ($this->identifier !== $rootId) {
112 try {
113 $readablePath = $this->getParentFolder()->getReadablePath($rootId);
114 } catch (Exception\InsufficientFolderAccessPermissionsException $e) {
115 // May no access to parent folder (e.g. because of mount point)
116 $readablePath = '/';
117 }
118 }
119 return $readablePath . ($this->name ? $this->name . '/' : '');
120 }
121
122 /**
123 * Sets a new name of the folder
124 * currently this does not trigger the "renaming process"
125 * as the name is more seen as a label
126 *
127 * @param string $name The new name
128 * @return void
129 */
130 public function setName($name)
131 {
132 $this->name = $name;
133 }
134
135 /**
136 * Returns the storage this folder belongs to.
137 *
138 * @return ResourceStorage
139 */
140 public function getStorage()
141 {
142 return $this->storage;
143 }
144
145 /**
146 * Returns the path of this folder inside the storage. It depends on the
147 * type of storage whether this is a real path or just some unique identifier.
148 *
149 * @return string
150 */
151 public function getIdentifier()
152 {
153 return $this->identifier;
154 }
155
156 /**
157 * Get hashed identifier
158 *
159 * @return string
160 */
161 public function getHashedIdentifier()
162 {
163 return $this->storage->hashFileIdentifier($this->identifier);
164 }
165
166 /**
167 * Returns a combined identifier of this folder, i.e. the storage UID and
168 * the folder identifier separated by a colon ":".
169 *
170 * @return string Combined storage and folder identifier, e.g. StorageUID:folder/path/
171 */
172 public function getCombinedIdentifier()
173 {
174 return $this->getStorage()->getUid() . ':' . $this->getIdentifier();
175 }
176
177 /**
178 * Returns a publicly accessible URL for this folder
179 *
180 * WARNING: Access to the folder may be restricted by further means, e.g. some
181 * web-based authentication. You have to take care of this yourself.
182 *
183 * @param bool $relativeToCurrentScript Determines whether the URL returned should be relative to the current script, in case it is relative at all (only for the LocalDriver)
184 * @return string
185 */
186 public function getPublicUrl($relativeToCurrentScript = false)
187 {
188 return $this->getStorage()->getPublicUrl($this, $relativeToCurrentScript);
189 }
190
191 /**
192 * Returns a list of files in this folder, optionally filtered. There are several filter modes available, see the
193 * FILTER_MODE_* constants for more information.
194 *
195 * For performance reasons the returned items can also be limited to a given range
196 *
197 * @param int $start The item to start at
198 * @param int $numberOfItems The number of items to return
199 * @param int $filterMode The filter mode to use for the filelist.
200 * @param bool $recursive
201 * @param string $sort Property name used to sort the items.
202 * Among them may be: '' (empty, no sorting), name,
203 * fileext, size, tstamp and rw.
204 * If a driver does not support the given property, it
205 * should fall back to "name".
206 * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
207 * @return \TYPO3\CMS\Core\Resource\File[]
208 */
209 public function getFiles($start = 0, $numberOfItems = 0, $filterMode = self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, $recursive = false, $sort = '', $sortRev = false)
210 {
211 // Fallback for compatibility with the old method signature variable $useFilters that was used instead of $filterMode
212 if ($filterMode === false) {
213 $useFilters = false;
214 $backedUpFilters = array();
215 } else {
216 list($backedUpFilters, $useFilters) = $this->prepareFiltersInStorage($filterMode);
217 }
218
219 $fileObjects = $this->storage->getFilesInFolder($this, $start, $numberOfItems, $useFilters, $recursive, $sort, $sortRev);
220
221 $this->restoreBackedUpFiltersInStorage($backedUpFilters);
222
223 return $fileObjects;
224 }
225
226 /**
227 * Returns amount of all files within this folder, optionally filtered by
228 * the given pattern
229 *
230 * @param array $filterMethods
231 * @param bool $recursive
232 * @return int
233 * @throws Exception\InsufficientFolderAccessPermissionsException
234 */
235 public function getFileCount(array $filterMethods = array(), $recursive = false)
236 {
237 return $this->storage->countFilesInFolder($this, true, $recursive);
238 }
239
240 /**
241 * Returns the object for a subfolder of the current folder, if it exists.
242 *
243 * @param string $name Name of the subfolder
244 * @return Folder
245 * @throws \InvalidArgumentException
246 */
247 public function getSubfolder($name)
248 {
249 if (!$this->storage->hasFolderInFolder($name, $this)) {
250 throw new \InvalidArgumentException('Folder "' . $name . '" does not exist in "' . $this->identifier . '"', 1329836110);
251 }
252 return $this->storage->getFolderInFolder($name, $this);
253 }
254
255 /**
256 * Returns a list of subfolders
257 *
258 * @param int $start The item to start at
259 * @param int $numberOfItems The number of items to return
260 * @param int $filterMode The filter mode to use for the filelist.
261 * @param bool $recursive
262 * @return Folder[]
263 */
264 public function getSubfolders($start = 0, $numberOfItems = 0, $filterMode = self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, $recursive = false)
265 {
266 list($backedUpFilters, $useFilters) = $this->prepareFiltersInStorage($filterMode);
267 $folderObjects = $this->storage->getFoldersInFolder($this, $start, $numberOfItems, $useFilters, $recursive);
268 $this->restoreBackedUpFiltersInStorage($backedUpFilters);
269 return $folderObjects;
270 }
271
272 /**
273 * Adds a file from the local server disk. If the file already exists and
274 * overwriting is disabled,
275 *
276 * @param string $localFilePath
277 * @param string $fileName
278 * @param string $conflictMode a value of the \TYPO3\CMS\Core\Resource\DuplicationBehavior enumeration
279 * @return File The file object
280 */
281 public function addFile($localFilePath, $fileName = null, $conflictMode = DuplicationBehavior::CANCEL)
282 {
283 $fileName = $fileName ? $fileName : PathUtility::basename($localFilePath);
284 return $this->storage->addFile($localFilePath, $this, $fileName, $conflictMode);
285 }
286
287 /**
288 * Adds an uploaded file into the Storage.
289 *
290 * @param array $uploadedFileData contains information about the uploaded file given by $_FILES['file1']
291 * @param string $conflictMode a value of the \TYPO3\CMS\Core\Resource\DuplicationBehavior enumeration
292 * @return File The file object
293 */
294 public function addUploadedFile(array $uploadedFileData, $conflictMode = DuplicationBehavior::CANCEL)
295 {
296 return $this->storage->addUploadedFile($uploadedFileData, $this, $uploadedFileData['name'], $conflictMode);
297 }
298
299 /**
300 * Renames this folder.
301 *
302 * @param string $newName
303 * @return Folder
304 */
305 public function rename($newName)
306 {
307 return $this->storage->renameFolder($this, $newName);
308 }
309
310 /**
311 * Deletes this folder from its storage. This also means that this object becomes useless.
312 *
313 * @param bool $deleteRecursively
314 * @return bool TRUE if deletion succeeded
315 */
316 public function delete($deleteRecursively = true)
317 {
318 return $this->storage->deleteFolder($this, $deleteRecursively);
319 }
320
321 /**
322 * Creates a new blank file
323 *
324 * @param string $fileName
325 * @return File The new file object
326 */
327 public function createFile($fileName)
328 {
329 return $this->storage->createFile($fileName, $this);
330 }
331
332 /**
333 * Creates a new folder
334 *
335 * @param string $folderName
336 * @return Folder The new folder object
337 */
338 public function createFolder($folderName)
339 {
340 return $this->storage->createFolder($folderName, $this);
341 }
342
343 /**
344 * Copies folder to a target folder
345 *
346 * @param Folder $targetFolder Target folder to copy to.
347 * @param string $targetFolderName an optional destination fileName
348 * @param string $conflictMode a value of the \TYPO3\CMS\Core\Resource\DuplicationBehavior enumeration
349 * @return Folder New (copied) folder object.
350 */
351 public function copyTo(Folder $targetFolder, $targetFolderName = null, $conflictMode = DuplicationBehavior::RENAME)
352 {
353 return $targetFolder->getStorage()->copyFolder($this, $targetFolder, $targetFolderName, $conflictMode);
354 }
355
356 /**
357 * Moves folder to a target folder
358 *
359 * @param Folder $targetFolder Target folder to move to.
360 * @param string $targetFolderName an optional destination fileName
361 * @param string $conflictMode a value of the \TYPO3\CMS\Core\Resource\DuplicationBehavior enumeration
362 * @return Folder New (copied) folder object.
363 */
364 public function moveTo(Folder $targetFolder, $targetFolderName = null, $conflictMode = DuplicationBehavior::RENAME)
365 {
366 return $targetFolder->getStorage()->moveFolder($this, $targetFolder, $targetFolderName, $conflictMode);
367 }
368
369 /**
370 * Checks if a file exists in this folder
371 *
372 * @param string $name
373 * @return bool
374 */
375 public function hasFile($name)
376 {
377 return $this->storage->hasFileInFolder($name, $this);
378 }
379
380 /**
381 * Checks if a folder exists in this folder.
382 *
383 * @param string $name
384 * @return bool
385 */
386 public function hasFolder($name)
387 {
388 return $this->storage->hasFolderInFolder($name, $this);
389 }
390
391 /**
392 * Check if a file operation (= action) is allowed on this folder
393 *
394 * @param string $action Action that can be read, write or delete
395 * @return bool
396 */
397 public function checkActionPermission($action)
398 {
399 try {
400 return $this->getStorage()->checkFolderActionPermission($action, $this);
401 } catch (Exception\ResourcePermissionsUnavailableException $e) {
402 return false;
403 }
404 }
405
406 /**
407 * Updates the properties of this folder, e.g. after re-indexing or moving it.
408 *
409 * NOTE: This method should not be called from outside the File Abstraction Layer (FAL)!
410 *
411 * @param array $properties
412 * @return void
413 * @internal
414 */
415 public function updateProperties(array $properties)
416 {
417 // Setting identifier and name to update values
418 if (isset($properties['identifier'])) {
419 $this->identifier = $properties['identifier'];
420 }
421 if (isset($properties['name'])) {
422 $this->name = $properties['name'];
423 }
424 }
425
426 /**
427 * Prepares the filters in this folder's storage according to a set filter mode.
428 *
429 * @param int $filterMode The filter mode to use; one of the FILTER_MODE_* constants
430 * @return array The backed up filters as an array (NULL if filters were not backed up) and whether to use filters or not (bool)
431 */
432 protected function prepareFiltersInStorage($filterMode)
433 {
434 $backedUpFilters = null;
435 $useFilters = true;
436
437 switch ($filterMode) {
438 case self::FILTER_MODE_USE_OWN_FILTERS:
439 $backedUpFilters = $this->storage->getFileAndFolderNameFilters();
440 $this->storage->setFileAndFolderNameFilters($this->fileAndFolderNameFilters);
441
442 break;
443
444 case self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS:
445 if (!empty($this->fileAndFolderNameFilters)) {
446 $backedUpFilters = $this->storage->getFileAndFolderNameFilters();
447 foreach ($this->fileAndFolderNameFilters as $filter) {
448 $this->storage->addFileAndFolderNameFilter($filter);
449 }
450 }
451
452 break;
453
454 case self::FILTER_MODE_USE_STORAGE_FILTERS:
455 // nothing to do here
456
457 break;
458
459 case self::FILTER_MODE_NO_FILTERS:
460 $useFilters = false;
461
462 break;
463 }
464 return array($backedUpFilters, $useFilters);
465 }
466
467 /**
468 * Restores the filters of a storage.
469 *
470 * @param array $backedUpFilters The filters to restore; might be NULL if no filters have been backed up, in
471 * which case this method does nothing.
472 * @see prepareFiltersInStorage()
473 */
474 protected function restoreBackedUpFiltersInStorage($backedUpFilters)
475 {
476 if ($backedUpFilters !== null) {
477 $this->storage->setFileAndFolderNameFilters($backedUpFilters);
478 }
479 }
480
481 /**
482 * Sets the filters to use when listing files. These are only used if the filter mode is one of
483 * FILTER_MODE_USE_OWN_FILTERS and FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS
484 *
485 * @param array $filters
486 */
487 public function setFileAndFolderNameFilters(array $filters)
488 {
489 $this->fileAndFolderNameFilters = $filters;
490 }
491
492 /**
493 * Returns the role of this folder (if any). See FolderInterface::ROLE_* constants for possible values.
494 *
495 * @return int
496 */
497 public function getRole()
498 {
499 return $this->storage->getRole($this);
500 }
501
502 /**
503 * Returns the parent folder.
504 *
505 * In non-hierarchical storages, that always is the root folder.
506 *
507 * The parent folder of the root folder is the root folder.
508 *
509 * @return Folder
510 */
511 public function getParentFolder()
512 {
513 return $this->getStorage()->getFolder($this->getStorage()->getFolderIdentifierFromFileIdentifier($this->getIdentifier()));
514 }
515
516 /**
517 * Returns the modification time of the file as Unix timestamp
518 *
519 * @return int
520 */
521 public function getModificationTime()
522 {
523 return $this->storage->getFolderInfo($this)['mtime'];
524 }
525
526 /**
527 * Returns the creation time of the file as Unix timestamp
528 *
529 * @return int
530 */
531 public function getCreationTime()
532 {
533 return $this->storage->getFolderInfo($this)['ctime'];
534 }
535 }