34bbec1ab6a41fd06ae949a30eb207a5562258f0
[Packages/TYPO3.CMS.git] / t3lib / file / Factory.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2011 Andreas Wolf <andreas.wolf@ikt-werk.de>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 * A copy is found in the textfile GPL.txt and important notices to the license
17 * from the author is found in LICENSE.txt distributed with these scripts.
18 *
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 ***************************************************************/
27
28
29 /**
30 * Factory class for FAL objects.
31 *
32 * NOTE: This class is part of the lowlevel FAL API and should not be used from outside the FAL package.
33 *
34 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
35 * @package TYPO3
36 * @subpackage t3lib
37 */
38
39 // TODO implement constructor-level caching
40 class t3lib_file_Factory implements t3lib_Singleton {
41
42 /**
43 * Gets a singleton instance of this class.
44 *
45 * @return t3lib_file_Factory
46 */
47 public static function getInstance() {
48 return t3lib_div::makeInstance('t3lib_file_Factory');
49 }
50
51 /**
52 * @var t3lib_file_Storage[]
53 */
54 protected $storageInstances = array();
55
56 /**
57 * @var t3lib_file_AbstractCollection[]
58 */
59 protected $collectionInstances = array();
60
61 /**
62 * @var t3lib_file_File[]
63 */
64 protected $fileInstances = array();
65
66 /**
67 * @var t3lib_file_FileReference[]
68 */
69 protected $fileReferenceInstances = array();
70
71 /**
72 * Creates a driver object for a specified storage object.
73 *
74 * @param string $driverIdentificationString The driver class (or identifier) to use.
75 * @param array $driverConfiguration The configuration of the storage
76 * @return t3lib_file_Driver_AbstractDriver
77 * @throws InvalidArgumentException
78 */
79 public function getDriverObject($driverIdentificationString, array $driverConfiguration) {
80 /** @var $driverRegistry t3lib_file_Driver_DriverRegistry */
81 $driverRegistry = t3lib_div::makeInstance('t3lib_file_Driver_DriverRegistry');
82 $driverClass = $driverRegistry->getDriverClass($driverIdentificationString);
83
84 $driverObject = t3lib_div::makeInstance($driverClass, $driverConfiguration);
85
86 return $driverObject;
87 }
88
89 /**
90 * Creates an instance of the storage from given UID. The $recordData can
91 * be supplied to increase performance.
92 *
93 * @param integer $uid The uid of the storage to instantiate.
94 * @param array $recordData The record row from database.
95 * @return t3lib_file_Storage
96 */
97 public function getStorageObject($uid, array $recordData = array()) {
98 if (!is_numeric($uid)) {
99 throw new InvalidArgumentException('uid of Storage has to be numeric.', 1314085991);
100 }
101
102 if (!$this->storageInstances[$uid]) {
103 $storageConfiguration = NULL;
104
105 // If the built-in storage with UID=0 is requested:
106 if (intval($uid) === 0) {
107 $recordData = array(
108 'uid' => 0,
109 'pid' => 0,
110 'name' => 'Default Storage',
111 'description' => 'Internal storage, mounting the main TYPO3_site directory.',
112 'driver' => 'Local',
113 'processingfolder' => 'typo3temp/_processed_/', // legacy code
114 'configuration' => '',
115 'is_online' => TRUE,
116 'is_browsable' => TRUE,
117 'is_public' => TRUE,
118 'is_writable' => TRUE,
119 );
120
121 $storageConfiguration = array(
122 'basePath' => '/',
123 'pathType' => 'relative'
124 );
125
126 // If any other (real) storage is requested:
127 // Get storage data if not already supplied as argument to this function
128 } elseif (count($recordData) === 0 || $recordData['uid'] !== $uid) {
129 /** @var $GLOBALS['TYPO3_DB'] t3lib_DB */
130 $recordData = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', 'sys_file_storage', 'uid=' . intval($uid) . ' AND deleted=0');
131 if (!is_array($recordData)) {
132 throw new InvalidArgumentException('No storage found for given UID.', 1314085992);
133 }
134 }
135
136 $storageObject = $this->createStorageObject($recordData, $storageConfiguration);
137 $this->storageInstances[$uid] = $storageObject;
138 }
139
140 return $this->storageInstances[$uid];
141 }
142
143 /**
144 * Converts a flexform data string to a flat array with key value pairs
145 *
146 * @param string $flexFormData
147 * @return array Array with key => value pairs of the field data in the FlexForm
148 */
149 public function convertFlexFormDataToConfigurationArray($flexFormData) {
150 $configuration = array();
151 if ($flexFormData) {
152 $flexFormContents = t3lib_div::xml2array($flexFormData);
153 if (!empty($flexFormContents['data']['sDEF']['lDEF']) && is_array($flexFormContents['data']['sDEF']['lDEF'])) {
154 foreach ($flexFormContents['data']['sDEF']['lDEF'] as $key => $value) {
155 if (isset($value['vDEF'])) {
156 $configuration[$key] = $value['vDEF'];
157 }
158 }
159 }
160 }
161
162 return $configuration;
163 }
164
165
166 /**
167 * Creates an instance of the collection from given UID. The $recordData can be supplied to increase performance.
168 *
169 * @param integer $uid The uid of the collection to instantiate.
170 * @param array $recordData The record row from database.
171 * @return t3lib_file_Collection_AbstractFileCollection
172 */
173 public function getCollectionObject($uid, array $recordData = array()) {
174 if (!is_numeric($uid)) {
175 throw new InvalidArgumentException('uid of collection has to be numeric.', 1314085999);
176 }
177
178 if (!$this->collectionInstances[$uid]) {
179 // Get mount data if not already supplied as argument to this function
180 if (count($recordData) === 0 || $recordData['uid'] !== $uid) {
181 /** @var $GLOBALS['TYPO3_DB'] t3lib_DB */
182 $recordData = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
183 '*',
184 'sys_file_collection',
185 'uid=' . intval($uid) . ' AND deleted=0'
186 );
187
188 if (!is_array($recordData)) {
189 throw new InvalidArgumentException('No collection found for given UID.', 1314085992);
190 }
191 }
192
193 $collectionObject = $this->createCollectionObject($recordData);
194 $this->collectionInstances[$uid] = $collectionObject;
195 }
196
197 return $this->collectionInstances[$uid];
198 }
199
200 /**
201 * Creates a collection object.
202 *
203 * @param array $collectionData The database row of the sys_file_collection record.
204 * @return t3lib_file_Collection_AbstractFileCollection
205 */
206 public function createCollectionObject(array $collectionData) {
207
208 switch ($collectionData['type']) {
209 case 'static':
210 $collection = t3lib_file_Collection_StaticFileCollection::create($collectionData);
211 break;
212 case 'folder':
213 $collection = t3lib_file_Collection_FolderBasedFileCollection::create($collectionData);
214 break;
215 default:
216 $collection = NULL;
217 }
218
219 return $collection;
220 }
221
222 /**
223 * Creates a storage object from a storage database row.
224 *
225 * @param array $storageRecord
226 * @param array $storageConfiguration Storage configuration (if given, this won't be extracted from the FlexForm value but the supplied array used instead)
227 * @return t3lib_file_Storage
228 */
229 public function createStorageObject(array $storageRecord, array $storageConfiguration=NULL) {
230 $className = 't3lib_file_Storage';
231
232 if (!$storageConfiguration) {
233 $storageConfiguration = $this->convertFlexFormDataToConfigurationArray($storageRecord['configuration']);
234 }
235
236 $driverType = $storageRecord['driver'];
237 $driverObject = $this->getDriverObject($driverType, $storageConfiguration);
238
239 /** @var $storage t3lib_file_Storage */
240 $storage = t3lib_div::makeInstance($className, $driverObject, $storageRecord);
241
242 // TODO handle publisher
243
244 return $storage;
245 }
246
247 /**
248 * Creates a folder to directly access (a part of) a storage.
249 *
250 * @param t3lib_file_Storage $storage The storage the folder belongs to
251 * @param string $identifier The path to the folder. Might also be a simple unique string, depending on the storage driver.
252 * @param string $name The name of the folder (e.g. the folder name)
253 * @return t3lib_file_Folder
254 */
255 public function createFolderObject(t3lib_file_Storage $storage, $identifier, $name) {
256 return t3lib_div::makeInstance('t3lib_file_Folder', $storage, $identifier, $name);
257 }
258
259 protected function createPublisherFromConfiguration(array $configuration) {
260 $publishingTarget = $this->getStorageObject($configuration['publisherConfiguration']['publishingTarget']);
261 $publisher = t3lib_div::makeInstance($configuration['publisher'], $publishingTarget, $configuration['publisherConfiguration']);
262 return $publisher;
263 }
264
265 /**
266 * Creates an instance of the file given UID. The $fileData can be supplied
267 * to increase performance.
268 *
269 * @param integer $uid The uid of the file to instantiate.
270 * @param array $fileData The record row from database.
271 * @return t3lib_file_File
272 */
273 public function getFileObject($uid, array $fileData = array()) {
274 if (!is_numeric($uid)) {
275 throw new InvalidArgumentException('uid of file has to be numeric.', 1300096564);
276 }
277
278 if (!$this->fileInstances[$uid]) {
279 // Fetches data in case $fileData is empty
280 if (empty($fileData)) {
281 /** @var $GLOBALS['TYPO3_DB'] t3lib_DB */
282 $fileData = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', 'sys_file', 'uid=' . intval($uid) . ' AND deleted=0');
283 if (!is_array($fileData)) {
284 throw new InvalidArgumentException('No file found for given UID.', 1317178604);
285 }
286 }
287
288 $this->fileInstances[$uid] = $this->createFileObject($fileData);
289 }
290
291 return $this->fileInstances[$uid];
292 }
293
294 /**
295 * Gets an file object from an identifier [storage]:[fileId]
296 *
297 * @param string $identifier
298 * @return t3lib_file_File
299 */
300 public function getFileObjectFromCombinedIdentifier($identifier) {
301 $parts = t3lib_div::trimExplode(':', $identifier);
302
303 if (count($parts) === 2) {
304 $storageUid = $parts[0];
305 $fileIdentifier = $parts[1];
306 } else {
307 // We only got a path: Go into backwards compatibility mode and
308 // use virtual Storage (uid=0)
309 $storageUid = 0;
310 $fileIdentifier = $parts[0];
311 }
312
313 return $this->getStorageObject($storageUid)->getFile($fileIdentifier);
314 }
315
316 /**
317 * Bulk function, can be used for anything to get a file or folder
318 *
319 * 1. It's a UID
320 * 2. It's a combined identifier
321 * 3. It's just a path/filename (coming from the oldstyle/backwards compatibility)
322 *
323 * Files, previously laid on fileadmin/ or something, will be "mapped" to the storage the file is
324 * in now. Files like typo3temp/ or typo3conf/ will be moved to the first writable storage
325 * in its processing folder
326 *
327 * $input could be
328 * - "2:myfolder/myfile.jpg" (combined identifier)
329 * - "23" (file UID)
330 * - "uploads/myfile.png" (backwards-compatibility, storage "0")
331 * - "file:23"
332 * @param string $input
333 * @return t3lib_file_FileInterface|t3lib_file_Folder
334 */
335 public function retrieveFileOrFolderObject($input) {
336 // Easy function to deal with that, could be dropped in the future
337 // if we know where to use this function
338 if (t3lib_div::isFirstPartOfStr($input, 'file:')) {
339 $input = substr($input, 5);
340 return $this->retrieveFileOrFolderObject($input);
341 } elseif (t3lib_utility_Math::canBeInterpretedAsInteger($input)) {
342 return $this->getFileObject($input);
343 } elseif (strpos($input, ':') > 0) {
344 list($prefix, $folderIdentifier) = explode(':', $input);
345 if (t3lib_utility_Math::canBeInterpretedAsInteger($prefix)) {
346 // path or folder in a valid storageUID
347 return $this->getObjectFromCombinedIdentifier($input);
348
349 } elseif ($prefix == 'EXT') {
350 $input = t3lib_div::getFileAbsFileName($input);
351 $input = t3lib_Utility_Path::getRelativePath(PATH_site, dirname($input)).basename($input);
352 return $this->getFileObjectFromCombinedIdentifier($input);
353 }
354 } else {
355 // only the path
356 return $this->getFileObjectFromCombinedIdentifier($input);
357 }
358 }
359
360
361 /**
362 * Gets an file object from an identifier [storage]:[fileId]
363 *
364 * @TODO check naming, inserted by SteffenR while working on filelist
365 * @param string $identifier
366 * @return t3lib_file_Folder
367 */
368 public function getFolderObjectFromCombinedIdentifier($identifier) {
369 $parts = t3lib_div::trimExplode(':', $identifier);
370
371 if (count($parts) === 2) {
372 $storageUid = $parts[0];
373 $folderIdentifier = $parts[1];
374 } else {
375 // We only got a path: Go into backwards compatibility mode and
376 // use virtual Storage (uid=0)
377 $storageUid = 0;
378 $folderIdentifier = substr($parts[0], strlen(PATH_site));
379 }
380
381 return $this->getStorageObject($storageUid)->getFolder($folderIdentifier);
382 }
383
384 /**
385 * Gets a file or folder object.
386 *
387 * @param string $identifier
388 * @return t3lib_file_FileInterface|t3lib_file_Folder
389 */
390 public function getObjectFromCombinedIdentifier($identifier) {
391 list($storageId, $objectIdentifier) = t3lib_div::trimExplode(':', $identifier);
392 $storage = $this->getStorageObject($storageId);
393
394 if ($storage->hasFile($objectIdentifier)) {
395 return $storage->getFile($objectIdentifier);
396 } elseif ($storage->hasFolder($objectIdentifier)) {
397 return $storage->getFolder($objectIdentifier);
398 } else {
399 throw new RuntimeException(
400 'Object with identifier "' . $identifier . '" does not exist in storage',
401 1329647780
402 );
403 }
404 }
405
406 /**
407 * Creates a file object from an array of file data. Requires a database
408 * row to be fetched.
409 *
410 * @param array $fileData
411 * @return t3lib_file_File
412 */
413 public function createFileObject(array $fileData) {
414 /** @var t3lib_file_File $fileObject */
415 $fileObject = t3lib_div::makeInstance('t3lib_file_File', $fileData);
416
417 if (is_numeric($fileData['storage'])) {
418 $storageObject = $this->getStorageObject($fileData['storage']);
419 $fileObject->setStorage($storageObject);
420 }
421
422 return $fileObject;
423 }
424
425 /**
426 * Creates an instance of a FileReference object. The $fileReferenceData can
427 * be supplied to increase performance.
428 *
429 * @param integer $uid The uid of the file usage (sys_file_reference) to instantiate.
430 * @param array $fileReferenceData The record row from database.
431 * @return t3lib_file_FileReference
432 */
433 public function getFileReferenceObject($uid, array $fileReferenceData = array()) {
434 if (!is_numeric($uid)) {
435 throw new InvalidArgumentException('uid of fileusage (sys_file_reference) has to be numeric.', 1300086584);
436 }
437
438
439 if (!$this->fileReferenceInstances[$uid]) {
440 // Fetches data in case $fileData is empty
441 if (empty($fileReferenceData)) {
442
443 // fetch the reference record of the current workspace
444 if (TYPO3_MODE === 'BE') {
445 $fileReferenceData = t3lib_BEfunc::getRecordWSOL('sys_file_reference', $uid);
446 } elseif (is_object($GLOBALS['TSFE'])) {
447 $fileReferenceData = $GLOBALS['TSFE']->sys_page->checkRecord('sys_file_reference', $uid);
448 } else {
449 /** @var $GLOBALS['TYPO3_DB'] t3lib_DB */
450 $fileReferenceData = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
451 '*',
452 'sys_file_reference',
453 'uid=' . intval($uid) . ' AND deleted=0'
454 );
455 }
456
457 if (!is_array($fileReferenceData)) {
458 throw new InvalidArgumentException('No fileusage (sys_file_reference) found for given UID.', 1317178794);
459 }
460 }
461
462 $this->fileReferenceInstances[$uid] = $this->createFileReferenceObject($fileReferenceData);
463 }
464
465 return $this->fileReferenceInstances[$uid];
466 }
467
468 /**
469 * Creates a file usage object from an array of fileReference data
470 * from sys_file_reference table.
471 * Requires a database row to be already fetched and present.
472 *
473 * @param array $fileReferenceData
474 * @return t3lib_file_FileReference
475 */
476 public function createFileReferenceObject(array $fileReferenceData) {
477 /** @var t3lib_file_FileReference $fileReferenceObject */
478 $fileReferenceObject = t3lib_div::makeInstance('t3lib_file_FileReference', $fileReferenceData);
479 return $fileReferenceObject;
480 }
481
482 /**
483 * Generates a new object of the type t3lib_file_ProcessedFile
484 * additionally checks if this processed file already exists in the DB
485 *
486 * @param t3lib_file_FileInterface $originalFileObject
487 * @param string $context The context the file is processed in
488 * @param array $configuration The processing configuration
489 * @return t3lib_file_ProcessedFile
490 */
491 public function getProcessedFileObject(t3lib_file_FileInterface $originalFileObject, $context, array $configuration) {
492 /** @var t3lib_file_ProcessedFile $processedFileObject */
493 $processedFileObject = t3lib_div::makeInstance(
494 't3lib_file_ProcessedFile',
495 $originalFileObject,
496 $context,
497 $configuration);
498
499 /* @var t3lib_file_Repository_ProcessedFileRepository $repository */
500 $repository = t3lib_div::makeInstance('t3lib_file_Repository_ProcessedFileRepository');
501
502 // Check if this file already exists in the DB
503 $repository->populateDataOfProcessedFileObject($processedFileObject);
504
505 return $processedFileObject;
506 }
507 }
508
509 ?>