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