[TASK] Remove sys_file.deleted flag and it's usage
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / Service / IndexerService.php
1 <?php
2 namespace TYPO3\CMS\Core\Resource\Service;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2011-2013 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 /**
30 * Indexer for the virtual file system
31 * should only be accessed through the FileRepository for now
32 *
33 * @author Andreas Wolf <andreas.wolf@ikt-werk.de>
34 */
35 class IndexerService implements \TYPO3\CMS\Core\SingletonInterface {
36
37 /**
38 * @var \TYPO3\CMS\Core\Resource\FileRepository
39 */
40 protected $repository;
41
42 /**
43 * @var \TYPO3\CMS\Core\Resource\ResourceFactory
44 */
45 protected $factory;
46
47 /**
48 * empty constructor, nothing to do here yet
49 */
50 public function __construct() {
51
52 }
53
54 /**
55 * Internal function to retrieve the file repository,
56 * if it does not exist, an instance will be created
57 *
58 * @return \TYPO3\CMS\Core\Resource\FileRepository
59 */
60 protected function getRepository() {
61 if ($this->repository === NULL) {
62 $this->repository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\FileRepository');
63 }
64 return $this->repository;
65 }
66
67 /**
68 * Setter function for the fileFactory
69 * returns the object itself for chaining purposes
70 *
71 * @param \TYPO3\CMS\Core\Resource\ResourceFactory $factory
72 * @return \TYPO3\CMS\Core\Resource\Service\IndexerService
73 */
74 public function setFactory(\TYPO3\CMS\Core\Resource\ResourceFactory $factory) {
75 $this->factory = $factory;
76 return $this;
77 }
78
79 /**
80 * Creates or updates a file index entry from a file object.
81 *
82 * @param \TYPO3\CMS\Core\Resource\File $fileObject
83 * @param bool $updateObject Set this to FALSE to get the indexed values. You have to take care of updating the object yourself then!
84 * @return \TYPO3\CMS\Core\Resource\File|array the indexed $fileObject or an array of indexed properties.
85 */
86 public function indexFile(\TYPO3\CMS\Core\Resource\File $fileObject, $updateObject = TRUE) {
87 // Get the file information of this object
88 $fileInfo = $this->gatherFileInformation($fileObject);
89 // Signal slot BEFORE the file was indexed
90 $this->emitPreFileIndexSignal($fileObject, $fileInfo);
91 // @todo: this should be done via services in the future
92 // @todo: this should take remote services into account
93 if ($fileInfo['type'] == $fileObject::FILETYPE_IMAGE && !$fileInfo['width']) {
94 $rawFileLocation = $fileObject->getForLocalProcessing(FALSE);
95 list($fileInfo['width'], $fileInfo['height']) = getimagesize($rawFileLocation);
96 }
97 // If the file is already indexed, then the file information will
98 // be updated on the existing record
99 if ($fileObject->isIndexed()) {
100 $GLOBALS['TYPO3_DB']->exec_UPDATEquery('sys_file', sprintf('uid = %d', $fileObject->getUid()), $fileInfo);
101 } else {
102 // Check if a file has been moved outside of FAL -- we have some
103 // orphaned index record in this case we could update
104 $otherFiles = $this->getRepository()->findBySha1Hash($fileInfo['sha1']);
105 $movedFile = FALSE;
106 /** @var $otherFile \TYPO3\CMS\Core\Resource\File */
107 foreach ($otherFiles as $otherFile) {
108 if (!$otherFile->exists()) {
109 // @todo: create a log entry
110 $movedFile = TRUE;
111 $otherFile->updateProperties($fileInfo);
112 $this->getRepository()->update($otherFile);
113 $fileInfo['uid'] = $otherFile->getUid();
114 $fileObject = $otherFile;
115 // Skip the rest of the files here as we might have more files that are missing, but we can only
116 // have one entry. The optimal solution would be to merge these records then, but this requires
117 // some more advanced logic that we currently have not implemented.
118 break;
119 }
120 }
121 // File was not moved, so it is a new index record
122 if ($movedFile === FALSE) {
123 // Crdate and tstamp should not be present when updating
124 // the file object, as they only relate to the index record
125 $additionalInfo = array(
126 'crdate' => $GLOBALS['EXEC_TIME'],
127 'tstamp' => $GLOBALS['EXEC_TIME']
128 );
129 if (TYPO3_MODE === 'BE') {
130 $additionalInfo['cruser_id'] = intval($GLOBALS['BE_USER']->user['uid']);
131 }
132 $indexRecord = array_merge($fileInfo, $additionalInfo);
133
134 $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_file', $indexRecord);
135 $fileInfo['uid'] = $GLOBALS['TYPO3_DB']->sql_insert_id();
136 }
137 }
138 // Check for an error during the execution and throw an exception
139 $error = $GLOBALS['TYPO3_DB']->sql_error();
140 if ($error) {
141 throw new \RuntimeException('Error during file indexing: "' . $error . '"', 1314455642);
142 }
143 // Signal slot AFTER the file was indexed
144 $this->emitPostFileIndexSignal($fileObject, $fileInfo);
145 if ($updateObject) {
146 $fileObject->updateProperties($fileInfo);
147 return $fileObject;
148 } else {
149 return $fileInfo;
150 }
151 }
152
153 /**
154 * Indexes an array of file objects
155 * currently this is done in a simple way, however could be changed to be more performant
156 *
157 * @param \TYPO3\CMS\Core\Resource\File[] $fileObjects
158 * @return void
159 */
160 public function indexFiles(array $fileObjects) {
161 // emit signal
162 $this->emitPreMultipleFilesIndexSignal($fileObjects);
163 foreach ($fileObjects as $fileObject) {
164 $this->indexFile($fileObject);
165 }
166 // emit signal
167 $this->emitPostMultipleFilesIndexSignal($fileObjects);
168 }
169
170 /**
171 * Indexes all files in a given storage folder.
172 * currently this is done in a simple way, however could be changed to be more performant
173 *
174 * @param \TYPO3\CMS\Core\Resource\Folder $folder
175 * @return int The number of indexed files.
176 */
177 public function indexFilesInFolder(\TYPO3\CMS\Core\Resource\Folder $folder) {
178 $numberOfIndexedFiles = 0;
179 // Index all files in this folder
180 $fileObjects = $folder->getFiles();
181 // emit signal
182 $this->emitPreMultipleFilesIndexSignal($fileObjects);
183 foreach ($fileObjects as $fileObject) {
184 $this->indexFile($fileObject);
185 $numberOfIndexedFiles++;
186 }
187 // emit signal
188 $this->emitPostMultipleFilesIndexSignal($fileObjects);
189 // Call this function recursively for each subfolder
190 $subFolders = $folder->getSubfolders();
191 foreach ($subFolders as $subFolder) {
192 $numberOfIndexedFiles += $this->indexFilesInFolder($subFolder);
193 }
194 return $numberOfIndexedFiles;
195 }
196
197 /**
198 * Fetches the information for a sys_file record
199 * based on a single file
200 * this function shouldn't be used, if someone needs to fetch the file information
201 * from a file object, should be done by getProperties etc
202 *
203 * @param \TYPO3\CMS\Core\Resource\File $file the file to fetch the information from
204 * @return array the file information as an array
205 */
206 protected function gatherFileInformation(\TYPO3\CMS\Core\Resource\File $file) {
207 $fileInfo = new \ArrayObject(array());
208 $gatherDefaultInformation = new \stdClass();
209 $gatherDefaultInformation->getDefaultFileInfo = 1;
210 // signal before the files are modified
211 $this->emitPreGatherFileInformationSignal($file, $fileInfo, $gatherDefaultInformation);
212 // the check helps you to disable the regular file fetching,
213 // so a signal could actually remotely access the service
214 if ($gatherDefaultInformation->getDefaultFileInfo) {
215 $storage = $file->getStorage();
216 // TODO: See if we can't just return info, as it contains most of the
217 // stuff we put together in array form again later here.
218 $info = $storage->getFileInfo($file);
219 $defaultFileInfo = array(
220 'creation_date' => $info['ctime'],
221 'modification_date' => $info['mtime'],
222 'size' => $info['size'],
223 'identifier' => $file->getIdentifier(),
224 'storage' => $storage->getUid(),
225 'name' => $file->getName(),
226 'sha1' => $storage->hashFile($file, 'sha1'),
227 'type' => $file->getType(),
228 'mime_type' => $file->getMimeType(),
229 'extension' => $file->getExtension()
230 );
231 $fileInfo = array_merge($defaultFileInfo, $fileInfo->getArrayCopy());
232 $fileInfo = new \ArrayObject($fileInfo);
233 }
234 // signal after the file information is fetched
235 $this->emitPostGatherFileInformationSignal($file, $fileInfo, $gatherDefaultInformation);
236 return $fileInfo->getArrayCopy();
237 }
238
239 /**
240 * Signal that is called before the file information is fetched
241 * helpful if somebody wants to preprocess the record information
242 *
243 * @param \TYPO3\CMS\Core\Resource\File $fileObject
244 * @param array $fileInfo
245 * @param boolean $gatherDefaultInformation
246 * @signal
247 */
248 protected function emitPreGatherFileInformationSignal(\TYPO3\CMS\Core\Resource\File $fileObject, $fileInfo, $gatherDefaultInformation) {
249 $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'preGatherFileInformation', array($fileObject, $fileInfo, $gatherDefaultInformation));
250 }
251
252 /**
253 * Signal that is called after a file object was indexed
254 *
255 * @param \TYPO3\CMS\Core\Resource\File $fileObject
256 * @param array $fileInfo
257 * @param boolean $hasGatheredDefaultInformation
258 * @signal
259 */
260 protected function emitPostGatherFileInformationSignal(\TYPO3\CMS\Core\Resource\File $fileObject, $fileInfo, $hasGatheredDefaultInformation) {
261 $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'postGatherFileInformation', array($fileObject, $fileInfo, $hasGatheredDefaultInformation));
262 }
263
264 /**
265 * Signal that is called before a bunch of file objects are indexed
266 *
267 * @param array $fileObject
268 * @signal
269 */
270 protected function emitPreMultipleFilesIndexSignal(array $fileObjectsToIndex) {
271 $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'preMultipleFileIndex', array($fileObjectsToIndex));
272 }
273
274 /**
275 * Signal that is called after multiple file objects were indexed
276 *
277 * @param array $fileObjectsToIndex
278 * @signal
279 */
280 protected function emitPostMultipleFilesIndexSignal(array $fileObjectsToIndex) {
281 $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'postMultipleFileIndex', array($fileObjectsToIndex));
282 }
283
284 /**
285 * Signal that is called before a file object was indexed
286 *
287 * @param \TYPO3\CMS\Core\Resource\File $fileObject
288 * @param array $fileInfo
289 * @signal
290 */
291 protected function emitPreFileIndexSignal(\TYPO3\CMS\Core\Resource\File $fileObject, $fileInfo) {
292 $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'preFileIndex', array($fileObject, $fileInfo));
293 }
294
295 /**
296 * Signal that is called after a file object was indexed
297 *
298 * @param \TYPO3\CMS\Core\Resource\File $fileObject
299 * @param array $fileInfo
300 * @signal
301 */
302 protected function emitPostFileIndexSignal(\TYPO3\CMS\Core\Resource\File $fileObject, $fileInfo) {
303 $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Service\\IndexerService', 'postFileIndex', array($fileObject, $fileInfo));
304 }
305
306 /**
307 * Get the SignalSlot dispatcher
308 *
309 * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
310 */
311 protected function getSignalSlotDispatcher() {
312 return $this->getObjectManager()->get('TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher');
313 }
314
315 /**
316 * Get the ObjectManager
317 *
318 * @return \TYPO3\CMS\Extbase\Object\ObjectManager
319 */
320 protected function getObjectManager() {
321 return \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
322 }
323
324 }
325
326
327 ?>