[TASK] Re-work/simplify copyright header in PHP files - Part 3
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / Index / FileIndexRepository.php
1 <?php
2
3 namespace TYPO3\CMS\Core\Resource\Index;
4
5 /**
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use TYPO3\CMS\Core\SingletonInterface;
19 use TYPO3\CMS\Core\Utility\GeneralUtility;
20 use TYPO3\CMS\Core\Resource\File;
21
22 /**
23 * Repository Class as an abstraction layer to sys_file
24 *
25 * Every access to table sys_file_metadata which is not handled by TCEmain
26 * has to use this Repository class.
27 *
28 * This is meant for FAL internal use only!.
29 */
30 class FileIndexRepository implements SingletonInterface {
31
32 /**
33 * @var string
34 */
35 protected $table = 'sys_file';
36
37 /**
38 * A list of properties which are to be persisted
39 *
40 * @var array
41 */
42 protected $fields = array(
43 'uid', 'pid', 'missing', 'type', 'storage', 'identifier', 'identifier_hash', 'extension',
44 'mime_type', 'name', 'sha1', 'size', 'creation_date', 'modification_date', 'folder_hash'
45 );
46
47 /**
48 * Gets database instance
49 *
50 * @return \TYPO3\CMS\Core\Database\DatabaseConnection
51 */
52 protected function getDatabaseConnection() {
53 return $GLOBALS['TYPO3_DB'];
54 }
55
56 /**
57 * Gets the Resource Factory
58 *
59 * @return \TYPO3\CMS\Core\Resource\ResourceFactory
60 */
61 protected function getResourceFactory() {
62 return \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance();
63 }
64
65
66 /**
67 * Returns an Instance of the Repository
68 *
69 * @return FileIndexRepository
70 */
71 public static function getInstance() {
72 return GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Index\\FileIndexRepository');
73 }
74
75 /**
76 * Retrieves Index record for a given $combinedIdentifier
77 *
78 * @param string $combinedIdentifier
79 * @return array|boolean
80 */
81 public function findOneByCombinedIdentifier($combinedIdentifier) {
82 list($storageUid, $identifier) = GeneralUtility::trimExplode(':', $combinedIdentifier, FALSE, 2);
83 return $this->findOneByStorageUidAndIdentifier($storageUid, $identifier);
84 }
85
86 /**
87 * Retrieves Index record for a given $fileUid
88 *
89 * @param int $fileUid
90 * @return array|boolean
91 */
92 public function findOneByUid($fileUid) {
93 $row = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
94 implode(',', $this->fields),
95 $this->table,
96 'uid=' . (int)$fileUid
97 );
98 return is_array($row) ? $row : FALSE;
99 }
100
101 /**
102 * Retrieves Index record for a given $storageUid and $identifier
103 *
104 * @param int $storageUid
105 * @param string $identifier
106 * @return array|boolean
107 *
108 * @internal only for use from FileRepository
109 */
110 public function findOneByStorageUidAndIdentifier($storageUid, $identifier) {
111 $identifierHash = $this->getResourceFactory()->getStorageObject($storageUid)->hashFileIdentifier($identifier);
112 return $this->findOneByStorageUidAndIdentifierHash($storageUid, $identifierHash);
113 }
114
115 /**
116 * Retrieves Index record for a given $storageUid and $identifier
117 *
118 * @param integer $storageUid
119 * @param string $identifierHash
120 * @return array|boolean
121 *
122 * @internal only for use from FileRepository
123 */
124 public function findOneByStorageUidAndIdentifierHash($storageUid, $identifierHash) {
125 $row = $this->getDatabaseConnection()->exec_SELECTgetSingleRow(
126 implode(',', $this->fields),
127 $this->table,
128 sprintf('storage=%u AND identifier_hash=%s', (int)$storageUid, $this->getDatabaseConnection()->fullQuoteStr($identifierHash, $this->table))
129 );
130 return is_array($row) ? $row : FALSE;
131 }
132
133 /**
134 * Retrieves Index record for a given $fileObject
135 *
136 * @param \TYPO3\CMS\Core\Resource\FileInterface $fileObject
137 * @return array|boolean
138 *
139 * @internal only for use from FileRepository
140 */
141 public function findOneByFileObject(\TYPO3\CMS\Core\Resource\FileInterface $fileObject) {
142 $storageUid = $fileObject->getStorage()->getUid();
143 $identifierHash = $fileObject->getHashedIdentifier();
144 return $this->findOneByStorageUidAndIdentifierHash($storageUid, $identifierHash);
145 }
146
147 /**
148 * Returns all indexed files which match the content hash
149 * Used by the indexer to detect already present files
150 *
151 * @param string $hash
152 * @return mixed
153 */
154 public function findByContentHash($hash) {
155 if (!preg_match('/^[0-9a-f]{40}$/i', $hash)) {
156 return array();
157 }
158 $resultRows = $this->getDatabaseConnection()->exec_SELECTgetRows(
159 implode(',', $this->fields),
160 $this->table,
161 'sha1=' . $this->getDatabaseConnection()->fullQuoteStr($hash, $this->table)
162 );
163 return $resultRows;
164 }
165
166 /**
167 * Find all records for files in a Folder
168 *
169 * @param \TYPO3\CMS\Core\Resource\Folder $folder
170 * @return array|NULL
171 */
172 public function findByFolder(\TYPO3\CMS\Core\Resource\Folder $folder) {
173 $resultRows = $this->getDatabaseConnection()->exec_SELECTgetRows(
174 implode(',', $this->fields),
175 $this->table,
176 'folder_hash = ' . $this->getDatabaseConnection()->fullQuoteStr($folder->getHashedIdentifier(), $this->table) .
177 ' AND storage = ' . (int)$folder->getStorage()->getUid(),
178 '',
179 '',
180 '',
181 'identifier'
182 );
183 return $resultRows;
184 }
185 /**
186 * Adds a file to the index
187 *
188 * @param File $file
189 * @return void
190 */
191 public function add(File $file) {
192 if ($this->hasIndexRecord($file)) {
193 $this->update($file);
194 if ($file->_getPropertyRaw('uid') === NULL) {
195 $file->updateProperties($this->findOneByFileObject($file));
196 }
197 } else {
198 $file->updateProperties(array('uid' => $this->insertRecord($file->getProperties())));
199 }
200 }
201
202 /**
203 * Add data from record (at indexing time)
204 *
205 * @param array $data
206 * @return array
207 */
208 public function addRaw(array $data) {
209 $data['uid'] = $this->insertRecord($data);
210 return $data;
211 }
212
213 /**
214 * Helper to reduce code duplication
215 *
216 * @param array $data
217 *
218 * @return integer
219 */
220 protected function insertRecord(array $data) {
221 $data = array_intersect_key($data, array_flip($this->fields));
222 $data['tstamp'] = time();
223 $this->getDatabaseConnection()->exec_INSERTquery($this->table, $data);
224 $data['uid'] = $this->getDatabaseConnection()->sql_insert_id();
225 $this->emitRecordCreatedSignal($data);
226 return $data['uid'];
227 }
228 /**
229 * Checks if a file is indexed
230 *
231 * @param File $file
232 * @return boolean
233 */
234 public function hasIndexRecord(File $file) {
235 return $this->getDatabaseConnection()->exec_SELECTcountRows('uid', $this->table, $this->getWhereClauseForFile($file)) >= 1;
236 }
237
238 /**
239 * Updates the index record in the database
240 *
241 * @param File $file
242 * @return void
243 */
244 public function update(File $file) {
245 $updatedProperties = array_intersect($this->fields, $file->getUpdatedProperties());
246 $updateRow = array();
247 foreach ($updatedProperties as $key) {
248 $updateRow[$key] = $file->getProperty($key);
249 }
250 if (count($updateRow) > 0) {
251 $updateRow['tstamp'] = time();
252 $this->getDatabaseConnection()->exec_UPDATEquery($this->table, $this->getWhereClauseForFile($file), $updateRow);
253 $this->emitRecordUpdatedSignal(array_intersect_key($file->getProperties(), array_flip($this->fields)));
254 }
255 }
256
257 /**
258 * Finds the files needed for second indexer step
259 *
260 * @param \TYPO3\CMS\Core\Resource\ResourceStorage $storage
261 * @param integer $limit
262 * @return array
263 */
264 public function findInStorageWithIndexOutstanding(\TYPO3\CMS\Core\Resource\ResourceStorage $storage, $limit = -1) {
265 return $this->getDatabaseConnection()->exec_SELECTgetRows(
266 implode(',', $this->fields),
267 $this->table,
268 'tstamp > last_indexed AND storage = ' . (int)$storage->getUid(),
269 '',
270 'tstamp ASC',
271 (int)$limit > 0 ? (int)$limit : ''
272 );
273 }
274
275
276 /**
277 * Helper function for the Indexer to detect missing files
278 *
279 * @param \TYPO3\CMS\Core\Resource\ResourceStorage $storage
280 * @param array $uidList
281 * @return array
282 */
283 public function findInStorageAndNotInUidList(\TYPO3\CMS\Core\Resource\ResourceStorage $storage, array $uidList) {
284 array_walk($uidList, 'intval');
285 $uidList = array_unique($uidList);
286
287 return $this->getDatabaseConnection()->exec_SELECTgetRows(
288 implode(',', $this->fields),
289 $this->table,
290 'storage = ' . (int)$storage->getUid() . ' AND uid NOT IN (' . implode(',', $uidList) . ')'
291 );
292 }
293
294 /**
295 * Updates the timestamp when the file indexer extracted metadata
296 *
297 * @param integer $fileUid
298 * @return void
299 */
300 public function updateIndexingTime($fileUid) {
301 $this->getDatabaseConnection()->exec_UPDATEquery($this->table, 'uid = ' . (int)$fileUid, array('last_indexed' => time()));
302 }
303
304 /**
305 * Marks given file as missing in sys_file
306 *
307 * @param integer $fileUid
308 * @return void
309 */
310 public function markFileAsMissing($fileUid) {
311 $this->getDatabaseConnection()->exec_UPDATEquery($this->table, 'uid = ' . (int)$fileUid, array('missing' => 1));
312 }
313
314 /**
315 * Returns a where clause to find a file in database
316 *
317 * @param File $file
318 *
319 * @return string
320 */
321 protected function getWhereClauseForFile(File $file) {
322 if ((int)$file->_getPropertyRaw('uid') > 0) {
323 $where = 'uid=' . (int)$file->getUid();
324 } else {
325 $where = sprintf(
326 'storage=%u AND identifier=%s',
327 (int)$file->getStorage()->getUid(),
328 $this->getDatabaseConnection()->fullQuoteStr($file->_getPropertyRaw('identifier'), $this->table)
329 );
330 }
331 return $where;
332 }
333
334 /**
335 * Remove a sys_file record from the database
336 *
337 * @param integer $fileUid
338 * @return void
339 */
340 public function remove($fileUid) {
341 $this->getDatabaseConnection()->exec_DELETEquery($this->table, 'uid=' . (int)$fileUid);
342 $this->emitRecordDeletedSignal($fileUid);
343 }
344
345 /*
346 * Get the SignalSlot dispatcher
347 *
348 * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
349 */
350 protected function getSignalSlotDispatcher() {
351 return $this->getObjectManager()->get('TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher');
352 }
353
354 /**
355 * Get the ObjectManager
356 *
357 * @return \TYPO3\CMS\Extbase\Object\ObjectManager
358 */
359 protected function getObjectManager() {
360 return \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
361 }
362
363
364
365 /**
366 * Signal that is called after an IndexRecord is updated
367 *
368 * @param array $data
369 * @signal
370 */
371 protected function emitRecordUpdatedSignal(array $data) {
372 $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Index\\FileIndexRepository', 'recordUpdated', array($data));
373 }
374
375 /**
376 * Signal that is called after an IndexRecord is created
377 *
378 * @param array $data
379 * @signal
380 */
381 protected function emitRecordCreatedSignal(array $data) {
382 $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Index\\FileIndexRepository', 'recordCreated', array($data));
383 }
384
385 /**
386 * Signal that is called after an IndexRecord is deleted
387 *
388 * @param integer $fileUid
389 * @signal
390 */
391 protected function emitRecordDeletedSignal($fileUid) {
392 $this->getSignalSlotDispatcher()->dispatch('TYPO3\\CMS\\Core\\Resource\\Index\\FileIndexRepository', 'recordDeleted', array($fileUid));
393 }
394 }