93f15a2a7d27a513a732089cd36f5ee24a10ad98
[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 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
32 * @author Ingmar Schlecht <ingmar@typo3.org>
33 */
34 class Folder implements FolderInterface {
35
36 /**
37 * The storage this folder belongs to.
38 *
39 * @var ResourceStorage
40 */
41 protected $storage;
42
43 /**
44 * The identifier of this folder to identify it on the storage.
45 * On some drivers, this is the path to the folder, but drivers could also just
46 * provide any other unique identifier for this folder on the specific storage.
47 *
48 * @var string
49 */
50 protected $identifier;
51
52 /**
53 * The name of this folder
54 *
55 * @var string
56 */
57 protected $name;
58
59 /**
60 * The filters this folder should use for a file list.
61 *
62 * @var callable[]
63 */
64 protected $fileAndFolderNameFilters = array();
65
66 /**
67 * Modes for filter usage in getFiles()/getFolders()
68 */
69 const FILTER_MODE_NO_FILTERS = 0;
70 // Merge local filters into storage's filters
71 const FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS = 1;
72 // Only use the filters provided by the storage
73 const FILTER_MODE_USE_STORAGE_FILTERS = 2;
74 // Only use the filters provided by the current class
75 const FILTER_MODE_USE_OWN_FILTERS = 3;
76
77 /**
78 * Initialization of the folder
79 *
80 * @param ResourceStorage $storage
81 * @param $identifier
82 * @param $name
83 */
84 public function __construct(ResourceStorage $storage, $identifier, $name) {
85 $this->storage = $storage;
86 $this->identifier = rtrim($identifier, '/') . '/';
87 $this->name = $name;
88 }
89
90 /**
91 * Returns the name of this folder.
92 *
93 * @return string
94 */
95 public function getName() {
96 return $this->name;
97 }
98
99 /**
100 * Sets a new name of the folder
101 * currently this does not trigger the "renaming process"
102 * as the name is more seen as a label
103 *
104 * @param string $name The new name
105 * @return void
106 */
107 public function setName($name) {
108 $this->name = $name;
109 }
110
111 /**
112 * Returns the storage this folder belongs to.
113 *
114 * @return ResourceStorage
115 */
116 public function getStorage() {
117 return $this->storage;
118 }
119
120 /**
121 * Returns the path of this folder inside the storage. It depends on the
122 * type of storage whether this is a real path or just some unique identifier.
123 *
124 * @return string
125 */
126 public function getIdentifier() {
127 return $this->identifier;
128 }
129
130 /**
131 * Get hashed identifier
132 *
133 * @return string
134 */
135 public function getHashedIdentifier() {
136 return $this->storage->hashFileIdentifier($this->identifier);
137 }
138
139 /**
140 * Returns a combined identifier of this folder, i.e. the storage UID and
141 * the folder identifier separated by a colon ":".
142 *
143 * @return string Combined storage and folder identifier, e.g. StorageUID:folder/path/
144 */
145 public function getCombinedIdentifier() {
146 return $this->getStorage()->getUid() . ':' . $this->getIdentifier();
147 }
148
149 /**
150 * Returns a publicly accessible URL for this folder
151 *
152 * WARNING: Access to the folder may be restricted by further means, e.g. some
153 * web-based authentication. You have to take care of this yourself.
154 *
155 * @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)
156 * @return string
157 */
158 public function getPublicUrl($relativeToCurrentScript = FALSE) {
159 return $this->getStorage()->getPublicUrl($this, $relativeToCurrentScript);
160 }
161
162 /**
163 * Returns a list of files in this folder, optionally filtered. There are several filter modes available, see the
164 * FILTER_MODE_* constants for more information.
165 *
166 * For performance reasons the returned items can also be limited to a given range
167 *
168 * @param int $start The item to start at
169 * @param int $numberOfItems The number of items to return
170 * @param int $filterMode The filter mode to use for the file list.
171 * @param bool $recursive
172 * @param string $sort Property name used to sort the items.
173 * Among them may be: '' (empty, no sorting), name,
174 * fileext, size, tstamp and rw.
175 * If a driver does not support the given property, it
176 * should fall back to "name".
177 * @param bool $sortRev TRUE to indicate reverse sorting (last to first)
178 * @return \TYPO3\CMS\Core\Resource\File[]
179 */
180 public function getFiles($start = 0, $numberOfItems = 0, $filterMode = self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS, $recursive = FALSE, $sort = '', $sortRev = FALSE) {
181 // Fallback for compatibility with the old method signature variable $useFilters that was used instead of $filterMode
182 if ($filterMode === FALSE) {
183 $useFilters = FALSE;
184 $backedUpFilters = array();
185 } else {
186 list($backedUpFilters, $useFilters) = $this->prepareFiltersInStorage($filterMode);
187 }
188
189 $fileObjects = $this->storage->getFilesInFolder($this, $start, $numberOfItems, $useFilters, $recursive, $sort, $sortRev);
190
191 $this->restoreBackedUpFiltersInStorage($backedUpFilters);
192
193 return $fileObjects;
194 }
195
196 /**
197 * Returns amount of all files within this folder, optionally filtered by
198 * the given pattern
199 *
200 * @param array $filterMethods
201 * @param bool $recursive
202 * @return int
203 */
204 public function getFileCount(array $filterMethods = array(), $recursive = FALSE) {
205 return $this->storage->countFilesInFolder($this, TRUE, $recursive);
206 }
207
208 /**
209 * Returns the object for a subfolder of the current folder, if it exists.
210 *
211 * @param string $name Name of the subfolder
212 * @return Folder
213 * @throws \InvalidArgumentException
214 */
215 public function getSubfolder($name) {
216 if (!$this->storage->hasFolderInFolder($name, $this)) {
217 throw new \InvalidArgumentException('Folder "' . $name . '" does not exist in "' . $this->identifier . '"', 1329836110);
218 }
219 /** @var $factory ResourceFactory */
220 $factory = ResourceFactory::getInstance();
221 $folderObject = $factory->createFolderObject($this->storage, $this->identifier . $name . '/', $name);
222 return $folderObject;
223 }
224
225 /**
226 * Returns a list of subfolders
227 *
228 * @param int $start The item to start at
229 * @param int $numberOfItems The number of items to return
230 * @param int $filterMode The filter mode to use for the file list.
231 * @return Folder[]
232 */
233 public function getSubfolders($start = 0, $numberOfItems = 0, $filterMode = self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS) {
234 list($backedUpFilters, $useFilters) = $this->prepareFiltersInStorage($filterMode);
235 $folderObjects = $this->storage->getFoldersInFolder($this, $start, $numberOfItems, $useFilters);
236 $this->restoreBackedUpFiltersInStorage($backedUpFilters);
237 return $folderObjects;
238 }
239
240 /**
241 * Adds a file from the local server disk. If the file already exists and
242 * overwriting is disabled,
243 *
244 * @param string $localFilePath
245 * @param string $fileName
246 * @param string $conflictMode possible value are 'cancel', 'replace', 'changeName'
247 * @return File The file object
248 */
249 public function addFile($localFilePath, $fileName = NULL, $conflictMode = 'cancel') {
250 $fileName = $fileName ? $fileName : PathUtility::basename($localFilePath);
251 return $this->storage->addFile($localFilePath, $this, $fileName, $conflictMode);
252 }
253
254 /**
255 * Adds an uploaded file into the Storage.
256 *
257 * @param array $uploadedFileData contains information about the uploaded file given by $_FILES['file1']
258 * @param string $conflictMode possible value are 'cancel', 'replace'
259 * @return File The file object
260 */
261 public function addUploadedFile(array $uploadedFileData, $conflictMode = 'cancel') {
262 return $this->storage->addUploadedFile($uploadedFileData, $this, $uploadedFileData['name'], $conflictMode);
263 }
264
265 /**
266 * Renames this folder.
267 *
268 * @param string $newName
269 * @return Folder
270 */
271 public function rename($newName) {
272 return $this->storage->renameFolder($this, $newName);
273 }
274
275 /**
276 * Deletes this folder from its storage. This also means that this object becomes useless.
277 *
278 * @param bool $deleteRecursively
279 * @return bool TRUE if deletion succeeded
280 */
281 public function delete($deleteRecursively = TRUE) {
282 return $this->storage->deleteFolder($this, $deleteRecursively);
283 }
284
285 /**
286 * Creates a new blank file
287 *
288 * @param string $fileName
289 * @return File The new file object
290 */
291 public function createFile($fileName) {
292 return $this->storage->createFile($fileName, $this);
293 }
294
295 /**
296 * Creates a new folder
297 *
298 * @param string $folderName
299 * @return Folder The new folder object
300 */
301 public function createFolder($folderName) {
302 return $this->storage->createFolder($folderName, $this);
303 }
304
305 /**
306 * Copies folder to a target folder
307 *
308 * @param Folder $targetFolder Target folder to copy to.
309 * @param string $targetFolderName an optional destination fileName
310 * @param string $conflictMode "overrideExistingFile", "renameNewFile" or "cancel
311 * @return Folder New (copied) folder object.
312 */
313 public function copyTo(Folder $targetFolder, $targetFolderName = NULL, $conflictMode = 'renameNewFile') {
314 return $targetFolder->getStorage()->copyFolder($this, $targetFolder, $targetFolderName, $conflictMode);
315 }
316
317 /**
318 * Moves folder to a target folder
319 *
320 * @param Folder $targetFolder Target folder to move to.
321 * @param string $targetFolderName an optional destination fileName
322 * @param string $conflictMode "overrideExistingFile", "renameNewFile" or "cancel
323 * @return Folder New (copied) folder object.
324 */
325 public function moveTo(Folder $targetFolder, $targetFolderName = NULL, $conflictMode = 'renameNewFile') {
326 return $targetFolder->getStorage()->moveFolder($this, $targetFolder, $targetFolderName, $conflictMode);
327 }
328
329 /**
330 * Checks if a file exists in this folder
331 *
332 * @param string $name
333 * @return bool
334 */
335 public function hasFile($name) {
336 return $this->storage->hasFileInFolder($name, $this);
337 }
338
339 /**
340 * Checks if a folder exists in this folder.
341 *
342 * @param string $name
343 * @return bool
344 */
345 public function hasFolder($name) {
346 return $this->storage->hasFolderInFolder($name, $this);
347 }
348
349 /**
350 * Check if a file operation (= action) is allowed on this folder
351 *
352 * @param string $action Action that can be read, write or delete
353 * @return bool
354 */
355 public function checkActionPermission($action) {
356 return $this->getStorage()->checkFolderActionPermission($action, $this);
357 }
358
359 /**
360 * Updates the properties of this folder, e.g. after re-indexing or moving it.
361 *
362 * NOTE: This method should not be called from outside the File Abstraction Layer (FAL)!
363 *
364 * @param array $properties
365 * @return void
366 * @internal
367 */
368 public function updateProperties(array $properties) {
369 // Setting identifier and name to update values
370 if (isset($properties['identifier'])) {
371 $this->identifier = $properties['identifier'];
372 }
373 if (isset($properties['name'])) {
374 $this->name = $properties['name'];
375 }
376 }
377
378 /**
379 * Prepares the filters in this folder's storage according to a set filter mode.
380 *
381 * @param int $filterMode The filter mode to use; one of the FILTER_MODE_* constants
382 * @return array The backed up filters as an array (NULL if filters were not backed up) and whether to use filters or not (bool)
383 */
384 protected function prepareFiltersInStorage($filterMode) {
385 $backedUpFilters = NULL;
386 $useFilters = TRUE;
387
388 switch ($filterMode) {
389 case self::FILTER_MODE_USE_OWN_FILTERS:
390 $backedUpFilters = $this->storage->getFileAndFolderNameFilters();
391 $this->storage->setFileAndFolderNameFilters($this->fileAndFolderNameFilters);
392
393 break;
394
395 case self::FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS:
396 if (count($this->fileAndFolderNameFilters) > 0) {
397 $backedUpFilters = $this->storage->getFileAndFolderNameFilters();
398 foreach ($this->fileAndFolderNameFilters as $filter) {
399 $this->storage->addFileAndFolderNameFilter($filter);
400 }
401 }
402
403 break;
404
405 case self::FILTER_MODE_USE_STORAGE_FILTERS:
406 // nothing to do here
407
408 break;
409
410 case self::FILTER_MODE_NO_FILTERS:
411 $useFilters = FALSE;
412
413 break;
414 }
415 return array($backedUpFilters, $useFilters);
416 }
417
418 /**
419 * Restores the filters of a storage.
420 *
421 * @param array $backedUpFilters The filters to restore; might be NULL if no filters have been backed up, in
422 * which case this method does nothing.
423 * @see prepareFiltersInStorage()
424 */
425 protected function restoreBackedUpFiltersInStorage($backedUpFilters) {
426 if ($backedUpFilters !== NULL) {
427 $this->storage->setFileAndFolderNameFilters($backedUpFilters);
428 }
429 }
430
431 /**
432 * Sets the filters to use when listing files. These are only used if the filter mode is one of
433 * FILTER_MODE_USE_OWN_FILTERS and FILTER_MODE_USE_OWN_AND_STORAGE_FILTERS
434 *
435 * @param array $filters
436 */
437 public function setFileAndFolderNameFilters(array $filters) {
438 $this->fileAndFolderNameFilters = $filters;
439 }
440
441 /**
442 * Returns the role of this folder (if any). See FolderInterface::ROLE_* constants for possible values.
443 *
444 * @return int
445 */
446 public function getRole() {
447 return $this->storage->getRole($this);
448 }
449
450 /**
451 * Returns the parent folder.
452 *
453 * In non-hierarchical storages, that always is the root folder.
454 *
455 * The parent folder of the root folder is the root folder.
456 *
457 * @return Folder
458 */
459 public function getParentFolder() {
460 return $this->getStorage()->getFolder($this->getStorage()->getFolderIdentifierFromFileIdentifier($this->getIdentifier()));
461 }
462
463 }