TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
FileIndexRepository.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Core\Resource\Index;
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 
29 
39 {
43  protected $table = 'sys_file';
44 
50  protected $fields = [
51  'uid', 'pid', 'missing', 'type', 'storage', 'identifier', 'identifier_hash', 'extension',
52  'mime_type', 'name', 'sha1', 'size', 'creation_date', 'modification_date', 'folder_hash'
53  ];
54 
60  protected function getResourceFactory()
61  {
63  }
64 
70  public static function getInstance()
71  {
72  return GeneralUtility::makeInstance(self::class);
73  }
74 
81  public function findOneByCombinedIdentifier($combinedIdentifier)
82  {
83  list($storageUid, $identifier) = GeneralUtility::trimExplode(':', $combinedIdentifier, false, 2);
84  return $this->findOneByStorageUidAndIdentifier($storageUid, $identifier);
85  }
86 
93  public function findOneByUid($fileUid)
94  {
95  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
96  ->getQueryBuilderForTable($this->table);
97 
98  $row = $queryBuilder
99  ->select(...$this->fields)
100  ->from($this->table)
101  ->where(
102  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($fileUid, \PDO::PARAM_INT))
103  )
104  ->execute()
105  ->fetch();
106 
107  return is_array($row) ? $row : false;
108  }
109 
119  public function findOneByStorageUidAndIdentifier($storageUid, $identifier)
120  {
121  $identifierHash = $this->getResourceFactory()->getStorageObject($storageUid)->hashFileIdentifier($identifier);
122  return $this->findOneByStorageUidAndIdentifierHash($storageUid, $identifierHash);
123  }
124 
134  public function findOneByStorageUidAndIdentifierHash($storageUid, $identifierHash)
135  {
136  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
137  ->getQueryBuilderForTable($this->table);
138 
139  $row = $queryBuilder
140  ->select(...$this->fields)
141  ->from($this->table)
142  ->where(
143  $queryBuilder->expr()->eq('storage', $queryBuilder->createNamedParameter($storageUid, \PDO::PARAM_INT)),
144  $queryBuilder->expr()->eq('identifier_hash', $queryBuilder->createNamedParameter($identifierHash))
145  )
146  ->execute()
147  ->fetch();
148 
149  return is_array($row) ? $row : false;
150  }
151 
160  public function findOneByFileObject(FileInterface $fileObject)
161  {
162  $storageUid = $fileObject->getStorage()->getUid();
163  $identifierHash = $fileObject->getHashedIdentifier();
164  return $this->findOneByStorageUidAndIdentifierHash($storageUid, $identifierHash);
165  }
166 
174  public function findByContentHash($hash)
175  {
176  if (!preg_match('/^[0-9a-f]{40}$/i', $hash)) {
177  return [];
178  }
179 
180  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
181  ->getQueryBuilderForTable($this->table);
182 
183  $resultRows = $queryBuilder
184  ->select(...$this->fields)
185  ->from($this->table)
186  ->where(
187  $queryBuilder->expr()->eq('sha1', $queryBuilder->createNamedParameter($hash, \PDO::PARAM_STR))
188  )
189  ->execute()
190  ->fetchAll();
191 
192  return $resultRows;
193  }
194 
201  public function findByFolder(Folder $folder)
202  {
203  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
204  ->getQueryBuilderForTable($this->table);
205 
206  $result = $queryBuilder
207  ->select(...$this->fields)
208  ->from($this->table)
209  ->where(
210  $queryBuilder->expr()->eq(
211  'folder_hash',
212  $queryBuilder->createNamedParameter($folder->getHashedIdentifier(), \PDO::PARAM_STR)
213  ),
214  $queryBuilder->expr()->eq(
215  'storage',
216  $queryBuilder->createNamedParameter($folder->getStorage()->getUid(), \PDO::PARAM_INT)
217  )
218  )
219  ->execute();
220 
221  $resultRows = [];
222  while ($row = $result->fetch()) {
223  $resultRows[$row['identifier']] = $row;
224  }
225 
226  return $resultRows;
227  }
228 
237  public function findByFolders(array $folders, $includeMissing = true, $fileName = null)
238  {
239  $storageUids = [];
240  $folderIdentifiers = [];
241 
242  foreach ($folders as $folder) {
243  if (!$folder instanceof Folder) {
244  continue;
245  }
246 
247  $storageUids[] = (int)$folder->getStorage()->getUid();
248  $folderIdentifiers[] = $folder->getHashedIdentifier();
249  }
250 
251  $storageUids = array_unique($storageUids);
252  $folderIdentifiers = array_unique($folderIdentifiers);
253 
254  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
255 
256  $queryBuilder
257  ->select(...$this->fields)
258  ->from($this->table)
259  ->where(
260  $queryBuilder->expr()->in(
261  'folder_hash',
262  $queryBuilder->createNamedParameter($folderIdentifiers, Connection::PARAM_STR_ARRAY)
263  ),
264  $queryBuilder->expr()->in(
265  'storage',
266  $queryBuilder->createNamedParameter($storageUids, Connection::PARAM_INT_ARRAY)
267  )
268  );
269 
270  if (isset($fileName)) {
271  $nameParts = str_getcsv($fileName, ' ');
272  foreach ($nameParts as $part) {
273  $part = trim($part);
274  if ($part !== '') {
275  $queryBuilder->andWhere(
276  $queryBuilder->expr()->like(
277  'name',
278  $queryBuilder->createNamedParameter('%' . $queryBuilder->escapeLikeWildcards($part) . '%',
279  \PDO::PARAM_STR)
280  )
281  );
282  }
283  }
284  }
285 
286  if (!$includeMissing) {
287  $queryBuilder->andWhere($queryBuilder->expr()->eq('missing', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT)));
288  }
289 
290  $result = $queryBuilder->execute();
291 
292  $fileRecords = [];
293  while ($fileRecord = $result->fetch()) {
294  $fileRecords[$fileRecord['identifier']] = $fileRecord;
295  }
296 
297  return $fileRecords;
298  }
299 
306  public function add(File $file)
307  {
308  if ($this->hasIndexRecord($file)) {
309  $this->update($file);
310  if ($file->_getPropertyRaw('uid') === null) {
311  $file->updateProperties($this->findOneByFileObject($file));
312  }
313  } else {
314  $file->updateProperties(['uid' => $this->insertRecord($file->getProperties())]);
315  }
316  }
317 
324  public function addRaw(array $data)
325  {
326  $data['uid'] = $this->insertRecord($data);
327  return $data;
328  }
329 
337  protected function insertRecord(array $data)
338  {
339  $data = array_intersect_key($data, array_flip($this->fields));
340  $data['tstamp'] = time();
341  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->table);
342  $connection->insert(
343  $this->table,
344  $data
345  );
346  $data['uid'] = $connection->lastInsertId($this->table);
347  $this->updateRefIndex($data['uid']);
348  $this->emitRecordCreatedSignal($data);
349  return $data['uid'];
350  }
351 
358  public function hasIndexRecord(File $file)
359  {
360  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
361 
362  if ((int)$file->_getPropertyRaw('uid') > 0) {
363  $constraints = [
364  $queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($file->getUid(), \PDO::PARAM_INT))
365  ];
366  } else {
367  $constraints = [
368  $queryBuilder->expr()->eq(
369  'storage',
370  $queryBuilder->createNamedParameter($file->getStorage()->getUid(), \PDO::PARAM_INT)
371  ),
372  $queryBuilder->expr()->eq(
373  'identifier',
374  $queryBuilder->createNamedParameter($file->_getPropertyRaw('identifier'), \PDO::PARAM_STR)
375  )
376  ];
377  }
378 
379  $count = $queryBuilder
380  ->count('uid')
381  ->from($this->table)
382  ->where(...$constraints)
383  ->execute()
384  ->fetchColumn(0);
385 
386  return (bool)$count;
387  }
388 
395  public function update(File $file)
396  {
397  $updatedProperties = array_intersect($this->fields, $file->getUpdatedProperties());
398  $updateRow = [];
399  foreach ($updatedProperties as $key) {
400  $updateRow[$key] = $file->getProperty($key);
401  }
402  if (!empty($updateRow)) {
403  if ((int)$file->_getPropertyRaw('uid') > 0) {
404  $constraints = ['uid' => (int)$file->getUid()];
405  } else {
406  $constraints = [
407  'storage' => (int)$file->getStorage()->getUid(),
408  'identifier' => $file->_getPropertyRaw('identifier')
409  ];
410  }
411 
412  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->table);
413  $updateRow['tstamp'] = time();
414 
415  $connection->update(
416  $this->table,
417  $updateRow,
418  $constraints
419  );
420 
421  $this->updateRefIndex($file->getUid());
422  $this->emitRecordUpdatedSignal(array_intersect_key($file->getProperties(), array_flip($this->fields)));
423  }
424  }
425 
433  public function findInStorageWithIndexOutstanding(ResourceStorage $storage, $limit = -1)
434  {
435  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
436 
437  if ((int)$limit > 0) {
438  $queryBuilder->setMaxResults((int)$limit);
439  }
440 
441  $rows = $queryBuilder
442  ->select(...$this->fields)
443  ->from($this->table)
444  ->where(
445  $queryBuilder->expr()->gt('tstamp', $queryBuilder->quoteIdentifier('last_indexed')),
446  $queryBuilder->expr()->eq('storage', $queryBuilder->createNamedParameter($storage->getUid(), \PDO::PARAM_INT))
447  )
448  ->orderBy('tstamp', 'ASC')
449  ->execute()
450  ->fetchAll();
451 
452  return $rows;
453  }
454 
462  public function findInStorageAndNotInUidList(ResourceStorage $storage, array $uidList)
463  {
464  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->table);
465 
466  $queryBuilder
467  ->select(...$this->fields)
468  ->from($this->table)
469  ->where(
470  $queryBuilder->expr()->eq(
471  'storage',
472  $queryBuilder->createNamedParameter($storage->getUid(), \PDO::PARAM_INT)
473  )
474  );
475 
476  if (!empty($uidList)) {
477  $queryBuilder->andWhere(
478  $queryBuilder->expr()->notIn(
479  'uid',
480  $queryBuilder->createNamedParameter($uidList, Connection::PARAM_INT_ARRAY)
481  )
482  );
483  }
484 
485  $rows = $queryBuilder->execute()->fetchAll();
486 
487  return $rows;
488  }
489 
496  public function updateIndexingTime($fileUid)
497  {
498  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->table);
499  $connection->update(
500  $this->table,
501  [
502  'last_indexed' => time()
503  ],
504  [
505  'uid' => (int)$fileUid
506  ]
507  );
508  }
509 
516  public function markFileAsMissing($fileUid)
517  {
518  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->table);
519  $connection->update(
520  $this->table,
521  [
522  'missing' => 1
523  ],
524  [
525  'uid' => (int)$fileUid
526  ]
527  );
528  $this->emitRecordMarkedAsMissingSignal($fileUid);
529  }
530 
537  public function remove($fileUid)
538  {
539  $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->table);
540  $connection->delete(
541  $this->table,
542  [
543  'uid' => (int)$fileUid
544  ]
545  );
546  $this->updateRefIndex($fileUid);
547  $this->emitRecordDeletedSignal($fileUid);
548  }
549 
556  public function updateRefIndex($id)
557  {
559  $refIndexObj = GeneralUtility::makeInstance(ReferenceIndex::class);
560  $refIndexObj->updateRefIndexTable($this->table, $id);
561  }
562 
563  /*
564  * Get the SignalSlot dispatcher
565  *
566  * @return Dispatcher
567  */
568  protected function getSignalSlotDispatcher()
569  {
570  return $this->getObjectManager()->get(Dispatcher::class);
571  }
572 
578  protected function getObjectManager()
579  {
580  return GeneralUtility::makeInstance(ObjectManager::class);
581  }
582 
589  protected function emitRecordUpdatedSignal(array $data)
590  {
591  $this->getSignalSlotDispatcher()->dispatch(self::class, 'recordUpdated', [$data]);
592  }
593 
600  protected function emitRecordCreatedSignal(array $data)
601  {
602  $this->getSignalSlotDispatcher()->dispatch(self::class, 'recordCreated', [$data]);
603  }
604 
611  protected function emitRecordDeletedSignal($fileUid)
612  {
613  $this->getSignalSlotDispatcher()->dispatch(self::class, 'recordDeleted', [$fileUid]);
614  }
615 
622  protected function emitRecordMarkedAsMissingSignal($fileUid)
623  {
624  $this->getSignalSlotDispatcher()->dispatch(self::class, 'recordMarkedAsMissing', [$fileUid]);
625  }
626 }
findOneByStorageUidAndIdentifierHash($storageUid, $identifierHash)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
findByFolders(array $folders, $includeMissing=true, $fileName=null)
findInStorageWithIndexOutstanding(ResourceStorage $storage, $limit=-1)
findInStorageAndNotInUidList(ResourceStorage $storage, array $uidList)
static makeInstance($className,...$constructorArguments)