Passed
Push — master ( 237c70...dcf686 )
by Morris
14:09
created
lib/private/Files/Cache/Cache.php 2 patches
Indentation   +838 added lines, -838 removed lines patch added patch discarded remove patch
@@ -57,852 +57,852 @@
 block discarded – undo
57 57
  * - ChangePropagator: updates the mtime and etags of parent folders whenever a change to the cache is made to the cache by the updater
58 58
  */
59 59
 class Cache implements ICache {
60
-	use MoveFromCacheTrait {
61
-		MoveFromCacheTrait::moveFromCache as moveFromCacheFallback;
62
-	}
63
-
64
-	/**
65
-	 * @var array partial data for the cache
66
-	 */
67
-	protected $partial = array();
68
-
69
-	/**
70
-	 * @var string
71
-	 */
72
-	protected $storageId;
73
-
74
-	/**
75
-	 * @var Storage $storageCache
76
-	 */
77
-	protected $storageCache;
78
-
79
-	/** @var IMimeTypeLoader */
80
-	protected $mimetypeLoader;
81
-
82
-	/**
83
-	 * @var IDBConnection
84
-	 */
85
-	protected $connection;
86
-
87
-	/** @var QuerySearchHelper */
88
-	protected $querySearchHelper;
89
-
90
-	/**
91
-	 * @param \OC\Files\Storage\Storage|string $storage
92
-	 */
93
-	public function __construct($storage) {
94
-		if ($storage instanceof \OC\Files\Storage\Storage) {
95
-			$this->storageId = $storage->getId();
96
-		} else {
97
-			$this->storageId = $storage;
98
-		}
99
-		if (strlen($this->storageId) > 64) {
100
-			$this->storageId = md5($this->storageId);
101
-		}
102
-
103
-		$this->storageCache = new Storage($storage);
104
-		$this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
105
-		$this->connection = \OC::$server->getDatabaseConnection();
106
-		$this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader);
107
-	}
108
-
109
-	/**
110
-	 * Get the numeric storage id for this cache's storage
111
-	 *
112
-	 * @return int
113
-	 */
114
-	public function getNumericStorageId() {
115
-		return $this->storageCache->getNumericId();
116
-	}
117
-
118
-	/**
119
-	 * get the stored metadata of a file or folder
120
-	 *
121
-	 * @param string | int $file either the path of a file or folder or the file id for a file or folder
122
-	 * @return ICacheEntry|false the cache entry as array of false if the file is not found in the cache
123
-	 */
124
-	public function get($file) {
125
-		if (is_string($file) or $file == '') {
126
-			// normalize file
127
-			$file = $this->normalize($file);
128
-
129
-			$where = 'WHERE `storage` = ? AND `path_hash` = ?';
130
-			$params = array($this->getNumericStorageId(), md5($file));
131
-		} else { //file id
132
-			$where = 'WHERE `fileid` = ?';
133
-			$params = array($file);
134
-		}
135
-		$sql = 'SELECT `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
60
+    use MoveFromCacheTrait {
61
+        MoveFromCacheTrait::moveFromCache as moveFromCacheFallback;
62
+    }
63
+
64
+    /**
65
+     * @var array partial data for the cache
66
+     */
67
+    protected $partial = array();
68
+
69
+    /**
70
+     * @var string
71
+     */
72
+    protected $storageId;
73
+
74
+    /**
75
+     * @var Storage $storageCache
76
+     */
77
+    protected $storageCache;
78
+
79
+    /** @var IMimeTypeLoader */
80
+    protected $mimetypeLoader;
81
+
82
+    /**
83
+     * @var IDBConnection
84
+     */
85
+    protected $connection;
86
+
87
+    /** @var QuerySearchHelper */
88
+    protected $querySearchHelper;
89
+
90
+    /**
91
+     * @param \OC\Files\Storage\Storage|string $storage
92
+     */
93
+    public function __construct($storage) {
94
+        if ($storage instanceof \OC\Files\Storage\Storage) {
95
+            $this->storageId = $storage->getId();
96
+        } else {
97
+            $this->storageId = $storage;
98
+        }
99
+        if (strlen($this->storageId) > 64) {
100
+            $this->storageId = md5($this->storageId);
101
+        }
102
+
103
+        $this->storageCache = new Storage($storage);
104
+        $this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
105
+        $this->connection = \OC::$server->getDatabaseConnection();
106
+        $this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader);
107
+    }
108
+
109
+    /**
110
+     * Get the numeric storage id for this cache's storage
111
+     *
112
+     * @return int
113
+     */
114
+    public function getNumericStorageId() {
115
+        return $this->storageCache->getNumericId();
116
+    }
117
+
118
+    /**
119
+     * get the stored metadata of a file or folder
120
+     *
121
+     * @param string | int $file either the path of a file or folder or the file id for a file or folder
122
+     * @return ICacheEntry|false the cache entry as array of false if the file is not found in the cache
123
+     */
124
+    public function get($file) {
125
+        if (is_string($file) or $file == '') {
126
+            // normalize file
127
+            $file = $this->normalize($file);
128
+
129
+            $where = 'WHERE `storage` = ? AND `path_hash` = ?';
130
+            $params = array($this->getNumericStorageId(), md5($file));
131
+        } else { //file id
132
+            $where = 'WHERE `fileid` = ?';
133
+            $params = array($file);
134
+        }
135
+        $sql = 'SELECT `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
136 136
 					   `storage_mtime`, `encrypted`, `etag`, `permissions`, `checksum`
137 137
 				FROM `*PREFIX*filecache` ' . $where;
138
-		$result = $this->connection->executeQuery($sql, $params);
139
-		$data = $result->fetch();
140
-
141
-		//FIXME hide this HACK in the next database layer, or just use doctrine and get rid of MDB2 and PDO
142
-		//PDO returns false, MDB2 returns null, oracle always uses MDB2, so convert null to false
143
-		if ($data === null) {
144
-			$data = false;
145
-		}
146
-
147
-		//merge partial data
148
-		if (!$data and is_string($file)) {
149
-			if (isset($this->partial[$file])) {
150
-				$data = $this->partial[$file];
151
-			}
152
-			return $data;
153
-		} else {
154
-			return self::cacheEntryFromData($data, $this->mimetypeLoader);
155
-		}
156
-	}
157
-
158
-	/**
159
-	 * Create a CacheEntry from database row
160
-	 *
161
-	 * @param array $data
162
-	 * @param IMimeTypeLoader $mimetypeLoader
163
-	 * @return CacheEntry
164
-	 */
165
-	public static function cacheEntryFromData($data, IMimeTypeLoader $mimetypeLoader) {
166
-		//fix types
167
-		$data['fileid'] = (int)$data['fileid'];
168
-		$data['parent'] = (int)$data['parent'];
169
-		$data['size'] = 0 + $data['size'];
170
-		$data['mtime'] = (int)$data['mtime'];
171
-		$data['storage_mtime'] = (int)$data['storage_mtime'];
172
-		$data['encryptedVersion'] = (int)$data['encrypted'];
173
-		$data['encrypted'] = (bool)$data['encrypted'];
174
-		$data['storage_id'] = $data['storage'];
175
-		$data['storage'] = (int)$data['storage'];
176
-		$data['mimetype'] = $mimetypeLoader->getMimetypeById($data['mimetype']);
177
-		$data['mimepart'] = $mimetypeLoader->getMimetypeById($data['mimepart']);
178
-		if ($data['storage_mtime'] == 0) {
179
-			$data['storage_mtime'] = $data['mtime'];
180
-		}
181
-		$data['permissions'] = (int)$data['permissions'];
182
-		return new CacheEntry($data);
183
-	}
184
-
185
-	/**
186
-	 * get the metadata of all files stored in $folder
187
-	 *
188
-	 * @param string $folder
189
-	 * @return ICacheEntry[]
190
-	 */
191
-	public function getFolderContents($folder) {
192
-		$fileId = $this->getId($folder);
193
-		return $this->getFolderContentsById($fileId);
194
-	}
195
-
196
-	/**
197
-	 * get the metadata of all files stored in $folder
198
-	 *
199
-	 * @param int $fileId the file id of the folder
200
-	 * @return ICacheEntry[]
201
-	 */
202
-	public function getFolderContentsById($fileId) {
203
-		if ($fileId > -1) {
204
-			$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
138
+        $result = $this->connection->executeQuery($sql, $params);
139
+        $data = $result->fetch();
140
+
141
+        //FIXME hide this HACK in the next database layer, or just use doctrine and get rid of MDB2 and PDO
142
+        //PDO returns false, MDB2 returns null, oracle always uses MDB2, so convert null to false
143
+        if ($data === null) {
144
+            $data = false;
145
+        }
146
+
147
+        //merge partial data
148
+        if (!$data and is_string($file)) {
149
+            if (isset($this->partial[$file])) {
150
+                $data = $this->partial[$file];
151
+            }
152
+            return $data;
153
+        } else {
154
+            return self::cacheEntryFromData($data, $this->mimetypeLoader);
155
+        }
156
+    }
157
+
158
+    /**
159
+     * Create a CacheEntry from database row
160
+     *
161
+     * @param array $data
162
+     * @param IMimeTypeLoader $mimetypeLoader
163
+     * @return CacheEntry
164
+     */
165
+    public static function cacheEntryFromData($data, IMimeTypeLoader $mimetypeLoader) {
166
+        //fix types
167
+        $data['fileid'] = (int)$data['fileid'];
168
+        $data['parent'] = (int)$data['parent'];
169
+        $data['size'] = 0 + $data['size'];
170
+        $data['mtime'] = (int)$data['mtime'];
171
+        $data['storage_mtime'] = (int)$data['storage_mtime'];
172
+        $data['encryptedVersion'] = (int)$data['encrypted'];
173
+        $data['encrypted'] = (bool)$data['encrypted'];
174
+        $data['storage_id'] = $data['storage'];
175
+        $data['storage'] = (int)$data['storage'];
176
+        $data['mimetype'] = $mimetypeLoader->getMimetypeById($data['mimetype']);
177
+        $data['mimepart'] = $mimetypeLoader->getMimetypeById($data['mimepart']);
178
+        if ($data['storage_mtime'] == 0) {
179
+            $data['storage_mtime'] = $data['mtime'];
180
+        }
181
+        $data['permissions'] = (int)$data['permissions'];
182
+        return new CacheEntry($data);
183
+    }
184
+
185
+    /**
186
+     * get the metadata of all files stored in $folder
187
+     *
188
+     * @param string $folder
189
+     * @return ICacheEntry[]
190
+     */
191
+    public function getFolderContents($folder) {
192
+        $fileId = $this->getId($folder);
193
+        return $this->getFolderContentsById($fileId);
194
+    }
195
+
196
+    /**
197
+     * get the metadata of all files stored in $folder
198
+     *
199
+     * @param int $fileId the file id of the folder
200
+     * @return ICacheEntry[]
201
+     */
202
+    public function getFolderContentsById($fileId) {
203
+        if ($fileId > -1) {
204
+            $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`,
205 205
 						   `storage_mtime`, `encrypted`, `etag`, `permissions`, `checksum`
206 206
 					FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC';
207
-			$result = $this->connection->executeQuery($sql, [$fileId]);
208
-			$files = $result->fetchAll();
209
-			return array_map(function (array $data) {
210
-				return self::cacheEntryFromData($data, $this->mimetypeLoader);
211
-			}, $files);
212
-		}
213
-		return [];
214
-	}
215
-
216
-	/**
217
-	 * insert or update meta data for a file or folder
218
-	 *
219
-	 * @param string $file
220
-	 * @param array $data
221
-	 *
222
-	 * @return int file id
223
-	 * @throws \RuntimeException
224
-	 */
225
-	public function put($file, array $data) {
226
-		if (($id = $this->getId($file)) > -1) {
227
-			$this->update($id, $data);
228
-			return $id;
229
-		} else {
230
-			return $this->insert($file, $data);
231
-		}
232
-	}
233
-
234
-	/**
235
-	 * insert meta data for a new file or folder
236
-	 *
237
-	 * @param string $file
238
-	 * @param array $data
239
-	 *
240
-	 * @return int file id
241
-	 * @throws \RuntimeException
242
-	 *
243
-	 * @suppress SqlInjectionChecker
244
-	 */
245
-	public function insert($file, array $data) {
246
-		// normalize file
247
-		$file = $this->normalize($file);
248
-
249
-		if (isset($this->partial[$file])) { //add any saved partial data
250
-			$data = array_merge($this->partial[$file], $data);
251
-			unset($this->partial[$file]);
252
-		}
253
-
254
-		$requiredFields = array('size', 'mtime', 'mimetype');
255
-		foreach ($requiredFields as $field) {
256
-			if (!isset($data[$field])) { //data not complete save as partial and return
257
-				$this->partial[$file] = $data;
258
-				return -1;
259
-			}
260
-		}
261
-
262
-		$data['path'] = $file;
263
-		$data['parent'] = $this->getParentId($file);
264
-		$data['name'] = basename($file);
265
-
266
-		list($queryParts, $params) = $this->buildParts($data);
267
-		$queryParts[] = '`storage`';
268
-		$params[] = $this->getNumericStorageId();
269
-
270
-		$queryParts = array_map(function ($item) {
271
-			return trim($item, "`");
272
-		}, $queryParts);
273
-		$values = array_combine($queryParts, $params);
274
-
275
-		try {
276
-			$builder = $this->connection->getQueryBuilder();
277
-			$builder->insert('filecache');
278
-
279
-			foreach ($values as $column => $value) {
280
-				$builder->setValue($column, $builder->createNamedParameter($value));
281
-			}
282
-
283
-			if ($builder->execute()) {
284
-				return (int)$this->connection->lastInsertId('*PREFIX*filecache');
285
-			}
286
-		} catch(UniqueConstraintViolationException $e) {
287
-			// entry exists already
288
-		}
289
-
290
-		// The file was created in the mean time
291
-		if (($id = $this->getId($file)) > -1) {
292
-			$this->update($id, $data);
293
-			return $id;
294
-		} else {
295
-			throw new \RuntimeException('File entry could not be inserted but could also not be selected with getId() in order to perform an update. Please try again.');
296
-		}
297
-	}
298
-
299
-	/**
300
-	 * update the metadata of an existing file or folder in the cache
301
-	 *
302
-	 * @param int $id the fileid of the existing file or folder
303
-	 * @param array $data [$key => $value] the metadata to update, only the fields provided in the array will be updated, non-provided values will remain unchanged
304
-	 */
305
-	public function update($id, array $data) {
306
-
307
-		if (isset($data['path'])) {
308
-			// normalize path
309
-			$data['path'] = $this->normalize($data['path']);
310
-		}
311
-
312
-		if (isset($data['name'])) {
313
-			// normalize path
314
-			$data['name'] = $this->normalize($data['name']);
315
-		}
316
-
317
-		list($queryParts, $params) = $this->buildParts($data);
318
-		// duplicate $params because we need the parts twice in the SQL statement
319
-		// once for the SET part, once in the WHERE clause
320
-		$params = array_merge($params, $params);
321
-		$params[] = $id;
322
-
323
-		// don't update if the data we try to set is the same as the one in the record
324
-		// some databases (Postgres) don't like superfluous updates
325
-		$sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? ' .
326
-			'WHERE (' .
327
-			implode(' <> ? OR ', $queryParts) . ' <> ? OR ' .
328
-			implode(' IS NULL OR ', $queryParts) . ' IS NULL' .
329
-			') AND `fileid` = ? ';
330
-		$this->connection->executeQuery($sql, $params);
331
-
332
-	}
333
-
334
-	/**
335
-	 * extract query parts and params array from data array
336
-	 *
337
-	 * @param array $data
338
-	 * @return array [$queryParts, $params]
339
-	 *        $queryParts: string[], the (escaped) column names to be set in the query
340
-	 *        $params: mixed[], the new values for the columns, to be passed as params to the query
341
-	 */
342
-	protected function buildParts(array $data) {
343
-		$fields = array(
344
-			'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted',
345
-			'etag', 'permissions', 'checksum', 'storage');
346
-
347
-		$doNotCopyStorageMTime = false;
348
-		if (array_key_exists('mtime', $data) && $data['mtime'] === null) {
349
-			// this horrific magic tells it to not copy storage_mtime to mtime
350
-			unset($data['mtime']);
351
-			$doNotCopyStorageMTime = true;
352
-		}
353
-
354
-		$params = array();
355
-		$queryParts = array();
356
-		foreach ($data as $name => $value) {
357
-			if (array_search($name, $fields) !== false) {
358
-				if ($name === 'path') {
359
-					$params[] = md5($value);
360
-					$queryParts[] = '`path_hash`';
361
-				} elseif ($name === 'mimetype') {
362
-					$params[] = $this->mimetypeLoader->getId(substr($value, 0, strpos($value, '/')));
363
-					$queryParts[] = '`mimepart`';
364
-					$value = $this->mimetypeLoader->getId($value);
365
-				} elseif ($name === 'storage_mtime') {
366
-					if (!$doNotCopyStorageMTime && !isset($data['mtime'])) {
367
-						$params[] = $value;
368
-						$queryParts[] = '`mtime`';
369
-					}
370
-				} elseif ($name === 'encrypted') {
371
-					if (isset($data['encryptedVersion'])) {
372
-						$value = $data['encryptedVersion'];
373
-					} else {
374
-						// Boolean to integer conversion
375
-						$value = $value ? 1 : 0;
376
-					}
377
-				}
378
-				$params[] = $value;
379
-				$queryParts[] = '`' . $name . '`';
380
-			}
381
-		}
382
-		return array($queryParts, $params);
383
-	}
384
-
385
-	/**
386
-	 * get the file id for a file
387
-	 *
388
-	 * A file id is a numeric id for a file or folder that's unique within an owncloud instance which stays the same for the lifetime of a file
389
-	 *
390
-	 * File ids are easiest way for apps to store references to a file since unlike paths they are not affected by renames or sharing
391
-	 *
392
-	 * @param string $file
393
-	 * @return int
394
-	 */
395
-	public function getId($file) {
396
-		// normalize file
397
-		$file = $this->normalize($file);
398
-
399
-		$pathHash = md5($file);
400
-
401
-		$sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
402
-		$result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
403
-		if ($row = $result->fetch()) {
404
-			return $row['fileid'];
405
-		} else {
406
-			return -1;
407
-		}
408
-	}
409
-
410
-	/**
411
-	 * get the id of the parent folder of a file
412
-	 *
413
-	 * @param string $file
414
-	 * @return int
415
-	 */
416
-	public function getParentId($file) {
417
-		if ($file === '') {
418
-			return -1;
419
-		} else {
420
-			$parent = $this->getParentPath($file);
421
-			return (int)$this->getId($parent);
422
-		}
423
-	}
424
-
425
-	private function getParentPath($path) {
426
-		$parent = dirname($path);
427
-		if ($parent === '.') {
428
-			$parent = '';
429
-		}
430
-		return $parent;
431
-	}
432
-
433
-	/**
434
-	 * check if a file is available in the cache
435
-	 *
436
-	 * @param string $file
437
-	 * @return bool
438
-	 */
439
-	public function inCache($file) {
440
-		return $this->getId($file) != -1;
441
-	}
442
-
443
-	/**
444
-	 * remove a file or folder from the cache
445
-	 *
446
-	 * when removing a folder from the cache all files and folders inside the folder will be removed as well
447
-	 *
448
-	 * @param string $file
449
-	 */
450
-	public function remove($file) {
451
-		$entry = $this->get($file);
452
-		$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?';
453
-		$this->connection->executeQuery($sql, array($entry['fileid']));
454
-		if ($entry['mimetype'] === 'httpd/unix-directory') {
455
-			$this->removeChildren($entry);
456
-		}
457
-	}
458
-
459
-	/**
460
-	 * Get all sub folders of a folder
461
-	 *
462
-	 * @param array $entry the cache entry of the folder to get the subfolders for
463
-	 * @return array[] the cache entries for the subfolders
464
-	 */
465
-	private function getSubFolders($entry) {
466
-		$children = $this->getFolderContentsById($entry['fileid']);
467
-		return array_filter($children, function ($child) {
468
-			return $child['mimetype'] === 'httpd/unix-directory';
469
-		});
470
-	}
471
-
472
-	/**
473
-	 * Recursively remove all children of a folder
474
-	 *
475
-	 * @param array $entry the cache entry of the folder to remove the children of
476
-	 * @throws \OC\DatabaseException
477
-	 */
478
-	private function removeChildren($entry) {
479
-		$subFolders = $this->getSubFolders($entry);
480
-		foreach ($subFolders as $folder) {
481
-			$this->removeChildren($folder);
482
-		}
483
-		$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `parent` = ?';
484
-		$this->connection->executeQuery($sql, array($entry['fileid']));
485
-	}
486
-
487
-	/**
488
-	 * Move a file or folder in the cache
489
-	 *
490
-	 * @param string $source
491
-	 * @param string $target
492
-	 */
493
-	public function move($source, $target) {
494
-		$this->moveFromCache($this, $source, $target);
495
-	}
496
-
497
-	/**
498
-	 * Get the storage id and path needed for a move
499
-	 *
500
-	 * @param string $path
501
-	 * @return array [$storageId, $internalPath]
502
-	 */
503
-	protected function getMoveInfo($path) {
504
-		return [$this->getNumericStorageId(), $path];
505
-	}
506
-
507
-	/**
508
-	 * Move a file or folder in the cache
509
-	 *
510
-	 * @param \OCP\Files\Cache\ICache $sourceCache
511
-	 * @param string $sourcePath
512
-	 * @param string $targetPath
513
-	 * @throws \OC\DatabaseException
514
-	 * @throws \Exception if the given storages have an invalid id
515
-	 * @suppress SqlInjectionChecker
516
-	 */
517
-	public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
518
-		if ($sourceCache instanceof Cache) {
519
-			// normalize source and target
520
-			$sourcePath = $this->normalize($sourcePath);
521
-			$targetPath = $this->normalize($targetPath);
522
-
523
-			$sourceData = $sourceCache->get($sourcePath);
524
-			$sourceId = $sourceData['fileid'];
525
-			$newParentId = $this->getParentId($targetPath);
526
-
527
-			list($sourceStorageId, $sourcePath) = $sourceCache->getMoveInfo($sourcePath);
528
-			list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath);
529
-
530
-			if (is_null($sourceStorageId) || $sourceStorageId === false) {
531
-				throw new \Exception('Invalid source storage id: ' . $sourceStorageId);
532
-			}
533
-			if (is_null($targetStorageId) || $targetStorageId === false) {
534
-				throw new \Exception('Invalid target storage id: ' . $targetStorageId);
535
-			}
536
-
537
-			$this->connection->beginTransaction();
538
-			if ($sourceData['mimetype'] === 'httpd/unix-directory') {
539
-				//update all child entries
540
-				$sourceLength = mb_strlen($sourcePath);
541
-				$query = $this->connection->getQueryBuilder();
542
-
543
-				$fun = $query->func();
544
-				$newPathFunction = $fun->concat(
545
-					$query->createNamedParameter($targetPath),
546
-					$fun->substring('path', $query->createNamedParameter($sourceLength + 1, IQueryBuilder::PARAM_INT))// +1 for the leading slash
547
-				);
548
-				$query->update('filecache')
549
-					->set('storage', $query->createNamedParameter($targetStorageId, IQueryBuilder::PARAM_INT))
550
-					->set('path_hash', $fun->md5($newPathFunction))
551
-					->set('path', $newPathFunction)
552
-					->where($query->expr()->eq('storage', $query->createNamedParameter($sourceStorageId, IQueryBuilder::PARAM_INT)))
553
-					->andWhere($query->expr()->like('path', $query->createNamedParameter($this->connection->escapeLikeParameter($sourcePath) . '/%')));
554
-
555
-				try {
556
-					$query->execute();
557
-				} catch (\OC\DatabaseException $e) {
558
-					$this->connection->rollBack();
559
-					throw $e;
560
-				}
561
-			}
562
-
563
-			$sql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` = ? WHERE `fileid` = ?';
564
-			$this->connection->executeQuery($sql, array($targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId));
565
-			$this->connection->commit();
566
-		} else {
567
-			$this->moveFromCacheFallback($sourceCache, $sourcePath, $targetPath);
568
-		}
569
-	}
570
-
571
-	/**
572
-	 * remove all entries for files that are stored on the storage from the cache
573
-	 */
574
-	public function clear() {
575
-		$sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?';
576
-		$this->connection->executeQuery($sql, array($this->getNumericStorageId()));
577
-
578
-		$sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?';
579
-		$this->connection->executeQuery($sql, array($this->storageId));
580
-	}
581
-
582
-	/**
583
-	 * Get the scan status of a file
584
-	 *
585
-	 * - Cache::NOT_FOUND: File is not in the cache
586
-	 * - Cache::PARTIAL: File is not stored in the cache but some incomplete data is known
587
-	 * - Cache::SHALLOW: The folder and it's direct children are in the cache but not all sub folders are fully scanned
588
-	 * - Cache::COMPLETE: The file or folder, with all it's children) are fully scanned
589
-	 *
590
-	 * @param string $file
591
-	 *
592
-	 * @return int Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
593
-	 */
594
-	public function getStatus($file) {
595
-		// normalize file
596
-		$file = $this->normalize($file);
597
-
598
-		$pathHash = md5($file);
599
-		$sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
600
-		$result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
601
-		if ($row = $result->fetch()) {
602
-			if ((int)$row['size'] === -1) {
603
-				return self::SHALLOW;
604
-			} else {
605
-				return self::COMPLETE;
606
-			}
607
-		} else {
608
-			if (isset($this->partial[$file])) {
609
-				return self::PARTIAL;
610
-			} else {
611
-				return self::NOT_FOUND;
612
-			}
613
-		}
614
-	}
615
-
616
-	/**
617
-	 * search for files matching $pattern
618
-	 *
619
-	 * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%')
620
-	 * @return ICacheEntry[] an array of cache entries where the name matches the search pattern
621
-	 */
622
-	public function search($pattern) {
623
-		// normalize pattern
624
-		$pattern = $this->normalize($pattern);
625
-
626
-		if ($pattern === '%%') {
627
-			return [];
628
-		}
629
-
630
-
631
-		$sql = '
207
+            $result = $this->connection->executeQuery($sql, [$fileId]);
208
+            $files = $result->fetchAll();
209
+            return array_map(function (array $data) {
210
+                return self::cacheEntryFromData($data, $this->mimetypeLoader);
211
+            }, $files);
212
+        }
213
+        return [];
214
+    }
215
+
216
+    /**
217
+     * insert or update meta data for a file or folder
218
+     *
219
+     * @param string $file
220
+     * @param array $data
221
+     *
222
+     * @return int file id
223
+     * @throws \RuntimeException
224
+     */
225
+    public function put($file, array $data) {
226
+        if (($id = $this->getId($file)) > -1) {
227
+            $this->update($id, $data);
228
+            return $id;
229
+        } else {
230
+            return $this->insert($file, $data);
231
+        }
232
+    }
233
+
234
+    /**
235
+     * insert meta data for a new file or folder
236
+     *
237
+     * @param string $file
238
+     * @param array $data
239
+     *
240
+     * @return int file id
241
+     * @throws \RuntimeException
242
+     *
243
+     * @suppress SqlInjectionChecker
244
+     */
245
+    public function insert($file, array $data) {
246
+        // normalize file
247
+        $file = $this->normalize($file);
248
+
249
+        if (isset($this->partial[$file])) { //add any saved partial data
250
+            $data = array_merge($this->partial[$file], $data);
251
+            unset($this->partial[$file]);
252
+        }
253
+
254
+        $requiredFields = array('size', 'mtime', 'mimetype');
255
+        foreach ($requiredFields as $field) {
256
+            if (!isset($data[$field])) { //data not complete save as partial and return
257
+                $this->partial[$file] = $data;
258
+                return -1;
259
+            }
260
+        }
261
+
262
+        $data['path'] = $file;
263
+        $data['parent'] = $this->getParentId($file);
264
+        $data['name'] = basename($file);
265
+
266
+        list($queryParts, $params) = $this->buildParts($data);
267
+        $queryParts[] = '`storage`';
268
+        $params[] = $this->getNumericStorageId();
269
+
270
+        $queryParts = array_map(function ($item) {
271
+            return trim($item, "`");
272
+        }, $queryParts);
273
+        $values = array_combine($queryParts, $params);
274
+
275
+        try {
276
+            $builder = $this->connection->getQueryBuilder();
277
+            $builder->insert('filecache');
278
+
279
+            foreach ($values as $column => $value) {
280
+                $builder->setValue($column, $builder->createNamedParameter($value));
281
+            }
282
+
283
+            if ($builder->execute()) {
284
+                return (int)$this->connection->lastInsertId('*PREFIX*filecache');
285
+            }
286
+        } catch(UniqueConstraintViolationException $e) {
287
+            // entry exists already
288
+        }
289
+
290
+        // The file was created in the mean time
291
+        if (($id = $this->getId($file)) > -1) {
292
+            $this->update($id, $data);
293
+            return $id;
294
+        } else {
295
+            throw new \RuntimeException('File entry could not be inserted but could also not be selected with getId() in order to perform an update. Please try again.');
296
+        }
297
+    }
298
+
299
+    /**
300
+     * update the metadata of an existing file or folder in the cache
301
+     *
302
+     * @param int $id the fileid of the existing file or folder
303
+     * @param array $data [$key => $value] the metadata to update, only the fields provided in the array will be updated, non-provided values will remain unchanged
304
+     */
305
+    public function update($id, array $data) {
306
+
307
+        if (isset($data['path'])) {
308
+            // normalize path
309
+            $data['path'] = $this->normalize($data['path']);
310
+        }
311
+
312
+        if (isset($data['name'])) {
313
+            // normalize path
314
+            $data['name'] = $this->normalize($data['name']);
315
+        }
316
+
317
+        list($queryParts, $params) = $this->buildParts($data);
318
+        // duplicate $params because we need the parts twice in the SQL statement
319
+        // once for the SET part, once in the WHERE clause
320
+        $params = array_merge($params, $params);
321
+        $params[] = $id;
322
+
323
+        // don't update if the data we try to set is the same as the one in the record
324
+        // some databases (Postgres) don't like superfluous updates
325
+        $sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? ' .
326
+            'WHERE (' .
327
+            implode(' <> ? OR ', $queryParts) . ' <> ? OR ' .
328
+            implode(' IS NULL OR ', $queryParts) . ' IS NULL' .
329
+            ') AND `fileid` = ? ';
330
+        $this->connection->executeQuery($sql, $params);
331
+
332
+    }
333
+
334
+    /**
335
+     * extract query parts and params array from data array
336
+     *
337
+     * @param array $data
338
+     * @return array [$queryParts, $params]
339
+     *        $queryParts: string[], the (escaped) column names to be set in the query
340
+     *        $params: mixed[], the new values for the columns, to be passed as params to the query
341
+     */
342
+    protected function buildParts(array $data) {
343
+        $fields = array(
344
+            'path', 'parent', 'name', 'mimetype', 'size', 'mtime', 'storage_mtime', 'encrypted',
345
+            'etag', 'permissions', 'checksum', 'storage');
346
+
347
+        $doNotCopyStorageMTime = false;
348
+        if (array_key_exists('mtime', $data) && $data['mtime'] === null) {
349
+            // this horrific magic tells it to not copy storage_mtime to mtime
350
+            unset($data['mtime']);
351
+            $doNotCopyStorageMTime = true;
352
+        }
353
+
354
+        $params = array();
355
+        $queryParts = array();
356
+        foreach ($data as $name => $value) {
357
+            if (array_search($name, $fields) !== false) {
358
+                if ($name === 'path') {
359
+                    $params[] = md5($value);
360
+                    $queryParts[] = '`path_hash`';
361
+                } elseif ($name === 'mimetype') {
362
+                    $params[] = $this->mimetypeLoader->getId(substr($value, 0, strpos($value, '/')));
363
+                    $queryParts[] = '`mimepart`';
364
+                    $value = $this->mimetypeLoader->getId($value);
365
+                } elseif ($name === 'storage_mtime') {
366
+                    if (!$doNotCopyStorageMTime && !isset($data['mtime'])) {
367
+                        $params[] = $value;
368
+                        $queryParts[] = '`mtime`';
369
+                    }
370
+                } elseif ($name === 'encrypted') {
371
+                    if (isset($data['encryptedVersion'])) {
372
+                        $value = $data['encryptedVersion'];
373
+                    } else {
374
+                        // Boolean to integer conversion
375
+                        $value = $value ? 1 : 0;
376
+                    }
377
+                }
378
+                $params[] = $value;
379
+                $queryParts[] = '`' . $name . '`';
380
+            }
381
+        }
382
+        return array($queryParts, $params);
383
+    }
384
+
385
+    /**
386
+     * get the file id for a file
387
+     *
388
+     * A file id is a numeric id for a file or folder that's unique within an owncloud instance which stays the same for the lifetime of a file
389
+     *
390
+     * File ids are easiest way for apps to store references to a file since unlike paths they are not affected by renames or sharing
391
+     *
392
+     * @param string $file
393
+     * @return int
394
+     */
395
+    public function getId($file) {
396
+        // normalize file
397
+        $file = $this->normalize($file);
398
+
399
+        $pathHash = md5($file);
400
+
401
+        $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
402
+        $result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
403
+        if ($row = $result->fetch()) {
404
+            return $row['fileid'];
405
+        } else {
406
+            return -1;
407
+        }
408
+    }
409
+
410
+    /**
411
+     * get the id of the parent folder of a file
412
+     *
413
+     * @param string $file
414
+     * @return int
415
+     */
416
+    public function getParentId($file) {
417
+        if ($file === '') {
418
+            return -1;
419
+        } else {
420
+            $parent = $this->getParentPath($file);
421
+            return (int)$this->getId($parent);
422
+        }
423
+    }
424
+
425
+    private function getParentPath($path) {
426
+        $parent = dirname($path);
427
+        if ($parent === '.') {
428
+            $parent = '';
429
+        }
430
+        return $parent;
431
+    }
432
+
433
+    /**
434
+     * check if a file is available in the cache
435
+     *
436
+     * @param string $file
437
+     * @return bool
438
+     */
439
+    public function inCache($file) {
440
+        return $this->getId($file) != -1;
441
+    }
442
+
443
+    /**
444
+     * remove a file or folder from the cache
445
+     *
446
+     * when removing a folder from the cache all files and folders inside the folder will be removed as well
447
+     *
448
+     * @param string $file
449
+     */
450
+    public function remove($file) {
451
+        $entry = $this->get($file);
452
+        $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `fileid` = ?';
453
+        $this->connection->executeQuery($sql, array($entry['fileid']));
454
+        if ($entry['mimetype'] === 'httpd/unix-directory') {
455
+            $this->removeChildren($entry);
456
+        }
457
+    }
458
+
459
+    /**
460
+     * Get all sub folders of a folder
461
+     *
462
+     * @param array $entry the cache entry of the folder to get the subfolders for
463
+     * @return array[] the cache entries for the subfolders
464
+     */
465
+    private function getSubFolders($entry) {
466
+        $children = $this->getFolderContentsById($entry['fileid']);
467
+        return array_filter($children, function ($child) {
468
+            return $child['mimetype'] === 'httpd/unix-directory';
469
+        });
470
+    }
471
+
472
+    /**
473
+     * Recursively remove all children of a folder
474
+     *
475
+     * @param array $entry the cache entry of the folder to remove the children of
476
+     * @throws \OC\DatabaseException
477
+     */
478
+    private function removeChildren($entry) {
479
+        $subFolders = $this->getSubFolders($entry);
480
+        foreach ($subFolders as $folder) {
481
+            $this->removeChildren($folder);
482
+        }
483
+        $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `parent` = ?';
484
+        $this->connection->executeQuery($sql, array($entry['fileid']));
485
+    }
486
+
487
+    /**
488
+     * Move a file or folder in the cache
489
+     *
490
+     * @param string $source
491
+     * @param string $target
492
+     */
493
+    public function move($source, $target) {
494
+        $this->moveFromCache($this, $source, $target);
495
+    }
496
+
497
+    /**
498
+     * Get the storage id and path needed for a move
499
+     *
500
+     * @param string $path
501
+     * @return array [$storageId, $internalPath]
502
+     */
503
+    protected function getMoveInfo($path) {
504
+        return [$this->getNumericStorageId(), $path];
505
+    }
506
+
507
+    /**
508
+     * Move a file or folder in the cache
509
+     *
510
+     * @param \OCP\Files\Cache\ICache $sourceCache
511
+     * @param string $sourcePath
512
+     * @param string $targetPath
513
+     * @throws \OC\DatabaseException
514
+     * @throws \Exception if the given storages have an invalid id
515
+     * @suppress SqlInjectionChecker
516
+     */
517
+    public function moveFromCache(ICache $sourceCache, $sourcePath, $targetPath) {
518
+        if ($sourceCache instanceof Cache) {
519
+            // normalize source and target
520
+            $sourcePath = $this->normalize($sourcePath);
521
+            $targetPath = $this->normalize($targetPath);
522
+
523
+            $sourceData = $sourceCache->get($sourcePath);
524
+            $sourceId = $sourceData['fileid'];
525
+            $newParentId = $this->getParentId($targetPath);
526
+
527
+            list($sourceStorageId, $sourcePath) = $sourceCache->getMoveInfo($sourcePath);
528
+            list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath);
529
+
530
+            if (is_null($sourceStorageId) || $sourceStorageId === false) {
531
+                throw new \Exception('Invalid source storage id: ' . $sourceStorageId);
532
+            }
533
+            if (is_null($targetStorageId) || $targetStorageId === false) {
534
+                throw new \Exception('Invalid target storage id: ' . $targetStorageId);
535
+            }
536
+
537
+            $this->connection->beginTransaction();
538
+            if ($sourceData['mimetype'] === 'httpd/unix-directory') {
539
+                //update all child entries
540
+                $sourceLength = mb_strlen($sourcePath);
541
+                $query = $this->connection->getQueryBuilder();
542
+
543
+                $fun = $query->func();
544
+                $newPathFunction = $fun->concat(
545
+                    $query->createNamedParameter($targetPath),
546
+                    $fun->substring('path', $query->createNamedParameter($sourceLength + 1, IQueryBuilder::PARAM_INT))// +1 for the leading slash
547
+                );
548
+                $query->update('filecache')
549
+                    ->set('storage', $query->createNamedParameter($targetStorageId, IQueryBuilder::PARAM_INT))
550
+                    ->set('path_hash', $fun->md5($newPathFunction))
551
+                    ->set('path', $newPathFunction)
552
+                    ->where($query->expr()->eq('storage', $query->createNamedParameter($sourceStorageId, IQueryBuilder::PARAM_INT)))
553
+                    ->andWhere($query->expr()->like('path', $query->createNamedParameter($this->connection->escapeLikeParameter($sourcePath) . '/%')));
554
+
555
+                try {
556
+                    $query->execute();
557
+                } catch (\OC\DatabaseException $e) {
558
+                    $this->connection->rollBack();
559
+                    throw $e;
560
+                }
561
+            }
562
+
563
+            $sql = 'UPDATE `*PREFIX*filecache` SET `storage` = ?, `path` = ?, `path_hash` = ?, `name` = ?, `parent` = ? WHERE `fileid` = ?';
564
+            $this->connection->executeQuery($sql, array($targetStorageId, $targetPath, md5($targetPath), basename($targetPath), $newParentId, $sourceId));
565
+            $this->connection->commit();
566
+        } else {
567
+            $this->moveFromCacheFallback($sourceCache, $sourcePath, $targetPath);
568
+        }
569
+    }
570
+
571
+    /**
572
+     * remove all entries for files that are stored on the storage from the cache
573
+     */
574
+    public function clear() {
575
+        $sql = 'DELETE FROM `*PREFIX*filecache` WHERE `storage` = ?';
576
+        $this->connection->executeQuery($sql, array($this->getNumericStorageId()));
577
+
578
+        $sql = 'DELETE FROM `*PREFIX*storages` WHERE `id` = ?';
579
+        $this->connection->executeQuery($sql, array($this->storageId));
580
+    }
581
+
582
+    /**
583
+     * Get the scan status of a file
584
+     *
585
+     * - Cache::NOT_FOUND: File is not in the cache
586
+     * - Cache::PARTIAL: File is not stored in the cache but some incomplete data is known
587
+     * - Cache::SHALLOW: The folder and it's direct children are in the cache but not all sub folders are fully scanned
588
+     * - Cache::COMPLETE: The file or folder, with all it's children) are fully scanned
589
+     *
590
+     * @param string $file
591
+     *
592
+     * @return int Cache::NOT_FOUND, Cache::PARTIAL, Cache::SHALLOW or Cache::COMPLETE
593
+     */
594
+    public function getStatus($file) {
595
+        // normalize file
596
+        $file = $this->normalize($file);
597
+
598
+        $pathHash = md5($file);
599
+        $sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
600
+        $result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
601
+        if ($row = $result->fetch()) {
602
+            if ((int)$row['size'] === -1) {
603
+                return self::SHALLOW;
604
+            } else {
605
+                return self::COMPLETE;
606
+            }
607
+        } else {
608
+            if (isset($this->partial[$file])) {
609
+                return self::PARTIAL;
610
+            } else {
611
+                return self::NOT_FOUND;
612
+            }
613
+        }
614
+    }
615
+
616
+    /**
617
+     * search for files matching $pattern
618
+     *
619
+     * @param string $pattern the search pattern using SQL search syntax (e.g. '%searchstring%')
620
+     * @return ICacheEntry[] an array of cache entries where the name matches the search pattern
621
+     */
622
+    public function search($pattern) {
623
+        // normalize pattern
624
+        $pattern = $this->normalize($pattern);
625
+
626
+        if ($pattern === '%%') {
627
+            return [];
628
+        }
629
+
630
+
631
+        $sql = '
632 632
 			SELECT `fileid`, `storage`, `path`, `parent`, `name`,
633 633
 				`mimetype`, `storage_mtime`, `mimepart`, `size`, `mtime`,
634 634
 				 `encrypted`, `etag`, `permissions`, `checksum`
635 635
 			FROM `*PREFIX*filecache`
636 636
 			WHERE `storage` = ? AND `name` ILIKE ?';
637
-		$result = $this->connection->executeQuery($sql,
638
-			[$this->getNumericStorageId(), $pattern]
639
-		);
640
-
641
-		return $this->searchResultToCacheEntries($result);
642
-	}
643
-
644
-	/**
645
-	 * @param Statement $result
646
-	 * @return CacheEntry[]
647
-	 */
648
-	private function searchResultToCacheEntries(Statement $result) {
649
-		$files = $result->fetchAll();
650
-
651
-		return array_map(function (array $data) {
652
-			return self::cacheEntryFromData($data, $this->mimetypeLoader);
653
-		}, $files);
654
-	}
655
-
656
-	/**
657
-	 * search for files by mimetype
658
-	 *
659
-	 * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image')
660
-	 *        where it will search for all mimetypes in the group ('image/*')
661
-	 * @return ICacheEntry[] an array of cache entries where the mimetype matches the search
662
-	 */
663
-	public function searchByMime($mimetype) {
664
-		if (strpos($mimetype, '/')) {
665
-			$where = '`mimetype` = ?';
666
-		} else {
667
-			$where = '`mimepart` = ?';
668
-		}
669
-		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `storage_mtime`, `mtime`, `encrypted`, `etag`, `permissions`, `checksum`
637
+        $result = $this->connection->executeQuery($sql,
638
+            [$this->getNumericStorageId(), $pattern]
639
+        );
640
+
641
+        return $this->searchResultToCacheEntries($result);
642
+    }
643
+
644
+    /**
645
+     * @param Statement $result
646
+     * @return CacheEntry[]
647
+     */
648
+    private function searchResultToCacheEntries(Statement $result) {
649
+        $files = $result->fetchAll();
650
+
651
+        return array_map(function (array $data) {
652
+            return self::cacheEntryFromData($data, $this->mimetypeLoader);
653
+        }, $files);
654
+    }
655
+
656
+    /**
657
+     * search for files by mimetype
658
+     *
659
+     * @param string $mimetype either a full mimetype to search ('text/plain') or only the first part of a mimetype ('image')
660
+     *        where it will search for all mimetypes in the group ('image/*')
661
+     * @return ICacheEntry[] an array of cache entries where the mimetype matches the search
662
+     */
663
+    public function searchByMime($mimetype) {
664
+        if (strpos($mimetype, '/')) {
665
+            $where = '`mimetype` = ?';
666
+        } else {
667
+            $where = '`mimepart` = ?';
668
+        }
669
+        $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `storage_mtime`, `mtime`, `encrypted`, `etag`, `permissions`, `checksum`
670 670
 				FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?';
671
-		$mimetype = $this->mimetypeLoader->getId($mimetype);
672
-		$result = $this->connection->executeQuery($sql, array($mimetype, $this->getNumericStorageId()));
673
-
674
-		return $this->searchResultToCacheEntries($result);
675
-	}
676
-
677
-	public function searchQuery(ISearchQuery $searchQuery) {
678
-		$builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
679
-
680
-		$query = $builder->select(['fileid', 'storage', 'path', 'parent', 'name', 'mimetype', 'mimepart', 'size', 'mtime', 'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum'])
681
-			->from('filecache', 'file');
682
-
683
-		$query->where($builder->expr()->eq('storage', $builder->createNamedParameter($this->getNumericStorageId())));
684
-
685
-		if ($this->querySearchHelper->shouldJoinTags($searchQuery->getSearchOperation())) {
686
-			$query
687
-				->innerJoin('file', 'vcategory_to_object', 'tagmap', $builder->expr()->eq('file.fileid', 'tagmap.objid'))
688
-				->innerJoin('tagmap', 'vcategory', 'tag', $builder->expr()->andX(
689
-					$builder->expr()->eq('tagmap.type', 'tag.type'),
690
-					$builder->expr()->eq('tagmap.categoryid', 'tag.id')
691
-				))
692
-				->andWhere($builder->expr()->eq('tag.type', $builder->createNamedParameter('files')))
693
-				->andWhere($builder->expr()->eq('tag.uid', $builder->createNamedParameter($searchQuery->getUser()->getUID())));
694
-		}
695
-
696
-		$query->andWhere($this->querySearchHelper->searchOperatorToDBExpr($builder, $searchQuery->getSearchOperation()));
697
-
698
-		$this->querySearchHelper->addSearchOrdersToQuery($query, $searchQuery->getOrder());
699
-
700
-		if ($searchQuery->getLimit()) {
701
-			$query->setMaxResults($searchQuery->getLimit());
702
-		}
703
-		if ($searchQuery->getOffset()) {
704
-			$query->setFirstResult($searchQuery->getOffset());
705
-		}
706
-
707
-		$result = $query->execute();
708
-		return $this->searchResultToCacheEntries($result);
709
-	}
710
-
711
-	/**
712
-	 * Search for files by tag of a given users.
713
-	 *
714
-	 * Note that every user can tag files differently.
715
-	 *
716
-	 * @param string|int $tag name or tag id
717
-	 * @param string $userId owner of the tags
718
-	 * @return ICacheEntry[] file data
719
-	 */
720
-	public function searchByTag($tag, $userId) {
721
-		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
722
-			'`mimetype`, `mimepart`, `size`, `mtime`, `storage_mtime`, ' .
723
-			'`encrypted`, `etag`, `permissions`, `checksum` ' .
724
-			'FROM `*PREFIX*filecache` `file`, ' .
725
-			'`*PREFIX*vcategory_to_object` `tagmap`, ' .
726
-			'`*PREFIX*vcategory` `tag` ' .
727
-			// JOIN filecache to vcategory_to_object
728
-			'WHERE `file`.`fileid` = `tagmap`.`objid` ' .
729
-			// JOIN vcategory_to_object to vcategory
730
-			'AND `tagmap`.`type` = `tag`.`type` ' .
731
-			'AND `tagmap`.`categoryid` = `tag`.`id` ' .
732
-			// conditions
733
-			'AND `file`.`storage` = ? ' .
734
-			'AND `tag`.`type` = \'files\' ' .
735
-			'AND `tag`.`uid` = ? ';
736
-		if (is_int($tag)) {
737
-			$sql .= 'AND `tag`.`id` = ? ';
738
-		} else {
739
-			$sql .= 'AND `tag`.`category` = ? ';
740
-		}
741
-		$result = $this->connection->executeQuery(
742
-			$sql,
743
-			[
744
-				$this->getNumericStorageId(),
745
-				$userId,
746
-				$tag
747
-			]
748
-		);
749
-
750
-		$files = $result->fetchAll();
751
-
752
-		return array_map(function (array $data) {
753
-			return self::cacheEntryFromData($data, $this->mimetypeLoader);
754
-		}, $files);
755
-	}
756
-
757
-	/**
758
-	 * Re-calculate the folder size and the size of all parent folders
759
-	 *
760
-	 * @param string|boolean $path
761
-	 * @param array $data (optional) meta data of the folder
762
-	 */
763
-	public function correctFolderSize($path, $data = null) {
764
-		$this->calculateFolderSize($path, $data);
765
-		if ($path !== '') {
766
-			$parent = dirname($path);
767
-			if ($parent === '.' or $parent === '/') {
768
-				$parent = '';
769
-			}
770
-			$this->correctFolderSize($parent);
771
-		}
772
-	}
773
-
774
-	/**
775
-	 * calculate the size of a folder and set it in the cache
776
-	 *
777
-	 * @param string $path
778
-	 * @param array $entry (optional) meta data of the folder
779
-	 * @return int
780
-	 */
781
-	public function calculateFolderSize($path, $entry = null) {
782
-		$totalSize = 0;
783
-		if (is_null($entry) or !isset($entry['fileid'])) {
784
-			$entry = $this->get($path);
785
-		}
786
-		if (isset($entry['mimetype']) && $entry['mimetype'] === 'httpd/unix-directory') {
787
-			$id = $entry['fileid'];
788
-			$sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 ' .
789
-				'FROM `*PREFIX*filecache` ' .
790
-				'WHERE `parent` = ? AND `storage` = ?';
791
-			$result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
792
-			if ($row = $result->fetch()) {
793
-				$result->closeCursor();
794
-				list($sum, $min) = array_values($row);
795
-				$sum = 0 + $sum;
796
-				$min = 0 + $min;
797
-				if ($min === -1) {
798
-					$totalSize = $min;
799
-				} else {
800
-					$totalSize = $sum;
801
-				}
802
-				$update = array();
803
-				if ($entry['size'] !== $totalSize) {
804
-					$update['size'] = $totalSize;
805
-				}
806
-				if (count($update) > 0) {
807
-					$this->update($id, $update);
808
-				}
809
-			} else {
810
-				$result->closeCursor();
811
-			}
812
-		}
813
-		return $totalSize;
814
-	}
815
-
816
-	/**
817
-	 * get all file ids on the files on the storage
818
-	 *
819
-	 * @return int[]
820
-	 */
821
-	public function getAll() {
822
-		$sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?';
823
-		$result = $this->connection->executeQuery($sql, array($this->getNumericStorageId()));
824
-		$ids = array();
825
-		while ($row = $result->fetch()) {
826
-			$ids[] = $row['fileid'];
827
-		}
828
-		return $ids;
829
-	}
830
-
831
-	/**
832
-	 * find a folder in the cache which has not been fully scanned
833
-	 *
834
-	 * If multiple incomplete folders are in the cache, the one with the highest id will be returned,
835
-	 * use the one with the highest id gives the best result with the background scanner, since that is most
836
-	 * likely the folder where we stopped scanning previously
837
-	 *
838
-	 * @return string|bool the path of the folder or false when no folder matched
839
-	 */
840
-	public function getIncomplete() {
841
-		$query = $this->connection->prepare('SELECT `path` FROM `*PREFIX*filecache`'
842
-			. ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC', 1);
843
-		$query->execute([$this->getNumericStorageId()]);
844
-		if ($row = $query->fetch()) {
845
-			return $row['path'];
846
-		} else {
847
-			return false;
848
-		}
849
-	}
850
-
851
-	/**
852
-	 * get the path of a file on this storage by it's file id
853
-	 *
854
-	 * @param int $id the file id of the file or folder to search
855
-	 * @return string|null the path of the file (relative to the storage) or null if a file with the given id does not exists within this cache
856
-	 */
857
-	public function getPathById($id) {
858
-		$sql = 'SELECT `path` FROM `*PREFIX*filecache` WHERE `fileid` = ? AND `storage` = ?';
859
-		$result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
860
-		if ($row = $result->fetch()) {
861
-			// Oracle stores empty strings as null...
862
-			if ($row['path'] === null) {
863
-				return '';
864
-			}
865
-			return $row['path'];
866
-		} else {
867
-			return null;
868
-		}
869
-	}
870
-
871
-	/**
872
-	 * get the storage id of the storage for a file and the internal path of the file
873
-	 * unlike getPathById this does not limit the search to files on this storage and
874
-	 * instead does a global search in the cache table
875
-	 *
876
-	 * @param int $id
877
-	 * @deprecated use getPathById() instead
878
-	 * @return array first element holding the storage id, second the path
879
-	 */
880
-	static public function getById($id) {
881
-		$connection = \OC::$server->getDatabaseConnection();
882
-		$sql = 'SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?';
883
-		$result = $connection->executeQuery($sql, array($id));
884
-		if ($row = $result->fetch()) {
885
-			$numericId = $row['storage'];
886
-			$path = $row['path'];
887
-		} else {
888
-			return null;
889
-		}
890
-
891
-		if ($id = Storage::getStorageId($numericId)) {
892
-			return array($id, $path);
893
-		} else {
894
-			return null;
895
-		}
896
-	}
897
-
898
-	/**
899
-	 * normalize the given path
900
-	 *
901
-	 * @param string $path
902
-	 * @return string
903
-	 */
904
-	public function normalize($path) {
905
-
906
-		return trim(\OC_Util::normalizeUnicode($path), '/');
907
-	}
671
+        $mimetype = $this->mimetypeLoader->getId($mimetype);
672
+        $result = $this->connection->executeQuery($sql, array($mimetype, $this->getNumericStorageId()));
673
+
674
+        return $this->searchResultToCacheEntries($result);
675
+    }
676
+
677
+    public function searchQuery(ISearchQuery $searchQuery) {
678
+        $builder = \OC::$server->getDatabaseConnection()->getQueryBuilder();
679
+
680
+        $query = $builder->select(['fileid', 'storage', 'path', 'parent', 'name', 'mimetype', 'mimepart', 'size', 'mtime', 'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum'])
681
+            ->from('filecache', 'file');
682
+
683
+        $query->where($builder->expr()->eq('storage', $builder->createNamedParameter($this->getNumericStorageId())));
684
+
685
+        if ($this->querySearchHelper->shouldJoinTags($searchQuery->getSearchOperation())) {
686
+            $query
687
+                ->innerJoin('file', 'vcategory_to_object', 'tagmap', $builder->expr()->eq('file.fileid', 'tagmap.objid'))
688
+                ->innerJoin('tagmap', 'vcategory', 'tag', $builder->expr()->andX(
689
+                    $builder->expr()->eq('tagmap.type', 'tag.type'),
690
+                    $builder->expr()->eq('tagmap.categoryid', 'tag.id')
691
+                ))
692
+                ->andWhere($builder->expr()->eq('tag.type', $builder->createNamedParameter('files')))
693
+                ->andWhere($builder->expr()->eq('tag.uid', $builder->createNamedParameter($searchQuery->getUser()->getUID())));
694
+        }
695
+
696
+        $query->andWhere($this->querySearchHelper->searchOperatorToDBExpr($builder, $searchQuery->getSearchOperation()));
697
+
698
+        $this->querySearchHelper->addSearchOrdersToQuery($query, $searchQuery->getOrder());
699
+
700
+        if ($searchQuery->getLimit()) {
701
+            $query->setMaxResults($searchQuery->getLimit());
702
+        }
703
+        if ($searchQuery->getOffset()) {
704
+            $query->setFirstResult($searchQuery->getOffset());
705
+        }
706
+
707
+        $result = $query->execute();
708
+        return $this->searchResultToCacheEntries($result);
709
+    }
710
+
711
+    /**
712
+     * Search for files by tag of a given users.
713
+     *
714
+     * Note that every user can tag files differently.
715
+     *
716
+     * @param string|int $tag name or tag id
717
+     * @param string $userId owner of the tags
718
+     * @return ICacheEntry[] file data
719
+     */
720
+    public function searchByTag($tag, $userId) {
721
+        $sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
722
+            '`mimetype`, `mimepart`, `size`, `mtime`, `storage_mtime`, ' .
723
+            '`encrypted`, `etag`, `permissions`, `checksum` ' .
724
+            'FROM `*PREFIX*filecache` `file`, ' .
725
+            '`*PREFIX*vcategory_to_object` `tagmap`, ' .
726
+            '`*PREFIX*vcategory` `tag` ' .
727
+            // JOIN filecache to vcategory_to_object
728
+            'WHERE `file`.`fileid` = `tagmap`.`objid` ' .
729
+            // JOIN vcategory_to_object to vcategory
730
+            'AND `tagmap`.`type` = `tag`.`type` ' .
731
+            'AND `tagmap`.`categoryid` = `tag`.`id` ' .
732
+            // conditions
733
+            'AND `file`.`storage` = ? ' .
734
+            'AND `tag`.`type` = \'files\' ' .
735
+            'AND `tag`.`uid` = ? ';
736
+        if (is_int($tag)) {
737
+            $sql .= 'AND `tag`.`id` = ? ';
738
+        } else {
739
+            $sql .= 'AND `tag`.`category` = ? ';
740
+        }
741
+        $result = $this->connection->executeQuery(
742
+            $sql,
743
+            [
744
+                $this->getNumericStorageId(),
745
+                $userId,
746
+                $tag
747
+            ]
748
+        );
749
+
750
+        $files = $result->fetchAll();
751
+
752
+        return array_map(function (array $data) {
753
+            return self::cacheEntryFromData($data, $this->mimetypeLoader);
754
+        }, $files);
755
+    }
756
+
757
+    /**
758
+     * Re-calculate the folder size and the size of all parent folders
759
+     *
760
+     * @param string|boolean $path
761
+     * @param array $data (optional) meta data of the folder
762
+     */
763
+    public function correctFolderSize($path, $data = null) {
764
+        $this->calculateFolderSize($path, $data);
765
+        if ($path !== '') {
766
+            $parent = dirname($path);
767
+            if ($parent === '.' or $parent === '/') {
768
+                $parent = '';
769
+            }
770
+            $this->correctFolderSize($parent);
771
+        }
772
+    }
773
+
774
+    /**
775
+     * calculate the size of a folder and set it in the cache
776
+     *
777
+     * @param string $path
778
+     * @param array $entry (optional) meta data of the folder
779
+     * @return int
780
+     */
781
+    public function calculateFolderSize($path, $entry = null) {
782
+        $totalSize = 0;
783
+        if (is_null($entry) or !isset($entry['fileid'])) {
784
+            $entry = $this->get($path);
785
+        }
786
+        if (isset($entry['mimetype']) && $entry['mimetype'] === 'httpd/unix-directory') {
787
+            $id = $entry['fileid'];
788
+            $sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 ' .
789
+                'FROM `*PREFIX*filecache` ' .
790
+                'WHERE `parent` = ? AND `storage` = ?';
791
+            $result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
792
+            if ($row = $result->fetch()) {
793
+                $result->closeCursor();
794
+                list($sum, $min) = array_values($row);
795
+                $sum = 0 + $sum;
796
+                $min = 0 + $min;
797
+                if ($min === -1) {
798
+                    $totalSize = $min;
799
+                } else {
800
+                    $totalSize = $sum;
801
+                }
802
+                $update = array();
803
+                if ($entry['size'] !== $totalSize) {
804
+                    $update['size'] = $totalSize;
805
+                }
806
+                if (count($update) > 0) {
807
+                    $this->update($id, $update);
808
+                }
809
+            } else {
810
+                $result->closeCursor();
811
+            }
812
+        }
813
+        return $totalSize;
814
+    }
815
+
816
+    /**
817
+     * get all file ids on the files on the storage
818
+     *
819
+     * @return int[]
820
+     */
821
+    public function getAll() {
822
+        $sql = 'SELECT `fileid` FROM `*PREFIX*filecache` WHERE `storage` = ?';
823
+        $result = $this->connection->executeQuery($sql, array($this->getNumericStorageId()));
824
+        $ids = array();
825
+        while ($row = $result->fetch()) {
826
+            $ids[] = $row['fileid'];
827
+        }
828
+        return $ids;
829
+    }
830
+
831
+    /**
832
+     * find a folder in the cache which has not been fully scanned
833
+     *
834
+     * If multiple incomplete folders are in the cache, the one with the highest id will be returned,
835
+     * use the one with the highest id gives the best result with the background scanner, since that is most
836
+     * likely the folder where we stopped scanning previously
837
+     *
838
+     * @return string|bool the path of the folder or false when no folder matched
839
+     */
840
+    public function getIncomplete() {
841
+        $query = $this->connection->prepare('SELECT `path` FROM `*PREFIX*filecache`'
842
+            . ' WHERE `storage` = ? AND `size` = -1 ORDER BY `fileid` DESC', 1);
843
+        $query->execute([$this->getNumericStorageId()]);
844
+        if ($row = $query->fetch()) {
845
+            return $row['path'];
846
+        } else {
847
+            return false;
848
+        }
849
+    }
850
+
851
+    /**
852
+     * get the path of a file on this storage by it's file id
853
+     *
854
+     * @param int $id the file id of the file or folder to search
855
+     * @return string|null the path of the file (relative to the storage) or null if a file with the given id does not exists within this cache
856
+     */
857
+    public function getPathById($id) {
858
+        $sql = 'SELECT `path` FROM `*PREFIX*filecache` WHERE `fileid` = ? AND `storage` = ?';
859
+        $result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
860
+        if ($row = $result->fetch()) {
861
+            // Oracle stores empty strings as null...
862
+            if ($row['path'] === null) {
863
+                return '';
864
+            }
865
+            return $row['path'];
866
+        } else {
867
+            return null;
868
+        }
869
+    }
870
+
871
+    /**
872
+     * get the storage id of the storage for a file and the internal path of the file
873
+     * unlike getPathById this does not limit the search to files on this storage and
874
+     * instead does a global search in the cache table
875
+     *
876
+     * @param int $id
877
+     * @deprecated use getPathById() instead
878
+     * @return array first element holding the storage id, second the path
879
+     */
880
+    static public function getById($id) {
881
+        $connection = \OC::$server->getDatabaseConnection();
882
+        $sql = 'SELECT `storage`, `path` FROM `*PREFIX*filecache` WHERE `fileid` = ?';
883
+        $result = $connection->executeQuery($sql, array($id));
884
+        if ($row = $result->fetch()) {
885
+            $numericId = $row['storage'];
886
+            $path = $row['path'];
887
+        } else {
888
+            return null;
889
+        }
890
+
891
+        if ($id = Storage::getStorageId($numericId)) {
892
+            return array($id, $path);
893
+        } else {
894
+            return null;
895
+        }
896
+    }
897
+
898
+    /**
899
+     * normalize the given path
900
+     *
901
+     * @param string $path
902
+     * @return string
903
+     */
904
+    public function normalize($path) {
905
+
906
+        return trim(\OC_Util::normalizeUnicode($path), '/');
907
+    }
908 908
 }
Please login to merge, or discard this patch.
Spacing   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -164,21 +164,21 @@  discard block
 block discarded – undo
164 164
 	 */
165 165
 	public static function cacheEntryFromData($data, IMimeTypeLoader $mimetypeLoader) {
166 166
 		//fix types
167
-		$data['fileid'] = (int)$data['fileid'];
168
-		$data['parent'] = (int)$data['parent'];
167
+		$data['fileid'] = (int) $data['fileid'];
168
+		$data['parent'] = (int) $data['parent'];
169 169
 		$data['size'] = 0 + $data['size'];
170
-		$data['mtime'] = (int)$data['mtime'];
171
-		$data['storage_mtime'] = (int)$data['storage_mtime'];
172
-		$data['encryptedVersion'] = (int)$data['encrypted'];
173
-		$data['encrypted'] = (bool)$data['encrypted'];
170
+		$data['mtime'] = (int) $data['mtime'];
171
+		$data['storage_mtime'] = (int) $data['storage_mtime'];
172
+		$data['encryptedVersion'] = (int) $data['encrypted'];
173
+		$data['encrypted'] = (bool) $data['encrypted'];
174 174
 		$data['storage_id'] = $data['storage'];
175
-		$data['storage'] = (int)$data['storage'];
175
+		$data['storage'] = (int) $data['storage'];
176 176
 		$data['mimetype'] = $mimetypeLoader->getMimetypeById($data['mimetype']);
177 177
 		$data['mimepart'] = $mimetypeLoader->getMimetypeById($data['mimepart']);
178 178
 		if ($data['storage_mtime'] == 0) {
179 179
 			$data['storage_mtime'] = $data['mtime'];
180 180
 		}
181
-		$data['permissions'] = (int)$data['permissions'];
181
+		$data['permissions'] = (int) $data['permissions'];
182 182
 		return new CacheEntry($data);
183 183
 	}
184 184
 
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
 					FROM `*PREFIX*filecache` WHERE `parent` = ? ORDER BY `name` ASC';
207 207
 			$result = $this->connection->executeQuery($sql, [$fileId]);
208 208
 			$files = $result->fetchAll();
209
-			return array_map(function (array $data) {
209
+			return array_map(function(array $data) {
210 210
 				return self::cacheEntryFromData($data, $this->mimetypeLoader);
211 211
 			}, $files);
212 212
 		}
@@ -267,7 +267,7 @@  discard block
 block discarded – undo
267 267
 		$queryParts[] = '`storage`';
268 268
 		$params[] = $this->getNumericStorageId();
269 269
 
270
-		$queryParts = array_map(function ($item) {
270
+		$queryParts = array_map(function($item) {
271 271
 			return trim($item, "`");
272 272
 		}, $queryParts);
273 273
 		$values = array_combine($queryParts, $params);
@@ -281,9 +281,9 @@  discard block
 block discarded – undo
281 281
 			}
282 282
 
283 283
 			if ($builder->execute()) {
284
-				return (int)$this->connection->lastInsertId('*PREFIX*filecache');
284
+				return (int) $this->connection->lastInsertId('*PREFIX*filecache');
285 285
 			}
286
-		} catch(UniqueConstraintViolationException $e) {
286
+		} catch (UniqueConstraintViolationException $e) {
287 287
 			// entry exists already
288 288
 		}
289 289
 
@@ -322,10 +322,10 @@  discard block
 block discarded – undo
322 322
 
323 323
 		// don't update if the data we try to set is the same as the one in the record
324 324
 		// some databases (Postgres) don't like superfluous updates
325
-		$sql = 'UPDATE `*PREFIX*filecache` SET ' . implode(' = ?, ', $queryParts) . '=? ' .
326
-			'WHERE (' .
327
-			implode(' <> ? OR ', $queryParts) . ' <> ? OR ' .
328
-			implode(' IS NULL OR ', $queryParts) . ' IS NULL' .
325
+		$sql = 'UPDATE `*PREFIX*filecache` SET '.implode(' = ?, ', $queryParts).'=? '.
326
+			'WHERE ('.
327
+			implode(' <> ? OR ', $queryParts).' <> ? OR '.
328
+			implode(' IS NULL OR ', $queryParts).' IS NULL'.
329 329
 			') AND `fileid` = ? ';
330 330
 		$this->connection->executeQuery($sql, $params);
331 331
 
@@ -376,7 +376,7 @@  discard block
 block discarded – undo
376 376
 					}
377 377
 				}
378 378
 				$params[] = $value;
379
-				$queryParts[] = '`' . $name . '`';
379
+				$queryParts[] = '`'.$name.'`';
380 380
 			}
381 381
 		}
382 382
 		return array($queryParts, $params);
@@ -418,7 +418,7 @@  discard block
 block discarded – undo
418 418
 			return -1;
419 419
 		} else {
420 420
 			$parent = $this->getParentPath($file);
421
-			return (int)$this->getId($parent);
421
+			return (int) $this->getId($parent);
422 422
 		}
423 423
 	}
424 424
 
@@ -464,7 +464,7 @@  discard block
 block discarded – undo
464 464
 	 */
465 465
 	private function getSubFolders($entry) {
466 466
 		$children = $this->getFolderContentsById($entry['fileid']);
467
-		return array_filter($children, function ($child) {
467
+		return array_filter($children, function($child) {
468 468
 			return $child['mimetype'] === 'httpd/unix-directory';
469 469
 		});
470 470
 	}
@@ -528,10 +528,10 @@  discard block
 block discarded – undo
528 528
 			list($targetStorageId, $targetPath) = $this->getMoveInfo($targetPath);
529 529
 
530 530
 			if (is_null($sourceStorageId) || $sourceStorageId === false) {
531
-				throw new \Exception('Invalid source storage id: ' . $sourceStorageId);
531
+				throw new \Exception('Invalid source storage id: '.$sourceStorageId);
532 532
 			}
533 533
 			if (is_null($targetStorageId) || $targetStorageId === false) {
534
-				throw new \Exception('Invalid target storage id: ' . $targetStorageId);
534
+				throw new \Exception('Invalid target storage id: '.$targetStorageId);
535 535
 			}
536 536
 
537 537
 			$this->connection->beginTransaction();
@@ -550,7 +550,7 @@  discard block
 block discarded – undo
550 550
 					->set('path_hash', $fun->md5($newPathFunction))
551 551
 					->set('path', $newPathFunction)
552 552
 					->where($query->expr()->eq('storage', $query->createNamedParameter($sourceStorageId, IQueryBuilder::PARAM_INT)))
553
-					->andWhere($query->expr()->like('path', $query->createNamedParameter($this->connection->escapeLikeParameter($sourcePath) . '/%')));
553
+					->andWhere($query->expr()->like('path', $query->createNamedParameter($this->connection->escapeLikeParameter($sourcePath).'/%')));
554 554
 
555 555
 				try {
556 556
 					$query->execute();
@@ -599,7 +599,7 @@  discard block
 block discarded – undo
599 599
 		$sql = 'SELECT `size` FROM `*PREFIX*filecache` WHERE `storage` = ? AND `path_hash` = ?';
600 600
 		$result = $this->connection->executeQuery($sql, array($this->getNumericStorageId(), $pathHash));
601 601
 		if ($row = $result->fetch()) {
602
-			if ((int)$row['size'] === -1) {
602
+			if ((int) $row['size'] === -1) {
603 603
 				return self::SHALLOW;
604 604
 			} else {
605 605
 				return self::COMPLETE;
@@ -648,7 +648,7 @@  discard block
 block discarded – undo
648 648
 	private function searchResultToCacheEntries(Statement $result) {
649 649
 		$files = $result->fetchAll();
650 650
 
651
-		return array_map(function (array $data) {
651
+		return array_map(function(array $data) {
652 652
 			return self::cacheEntryFromData($data, $this->mimetypeLoader);
653 653
 		}, $files);
654 654
 	}
@@ -667,7 +667,7 @@  discard block
 block discarded – undo
667 667
 			$where = '`mimepart` = ?';
668 668
 		}
669 669
 		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `storage_mtime`, `mtime`, `encrypted`, `etag`, `permissions`, `checksum`
670
-				FROM `*PREFIX*filecache` WHERE ' . $where . ' AND `storage` = ?';
670
+				FROM `*PREFIX*filecache` WHERE ' . $where.' AND `storage` = ?';
671 671
 		$mimetype = $this->mimetypeLoader->getId($mimetype);
672 672
 		$result = $this->connection->executeQuery($sql, array($mimetype, $this->getNumericStorageId()));
673 673
 
@@ -718,20 +718,20 @@  discard block
 block discarded – undo
718 718
 	 * @return ICacheEntry[] file data
719 719
 	 */
720 720
 	public function searchByTag($tag, $userId) {
721
-		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, ' .
722
-			'`mimetype`, `mimepart`, `size`, `mtime`, `storage_mtime`, ' .
723
-			'`encrypted`, `etag`, `permissions`, `checksum` ' .
724
-			'FROM `*PREFIX*filecache` `file`, ' .
725
-			'`*PREFIX*vcategory_to_object` `tagmap`, ' .
726
-			'`*PREFIX*vcategory` `tag` ' .
721
+		$sql = 'SELECT `fileid`, `storage`, `path`, `parent`, `name`, '.
722
+			'`mimetype`, `mimepart`, `size`, `mtime`, `storage_mtime`, '.
723
+			'`encrypted`, `etag`, `permissions`, `checksum` '.
724
+			'FROM `*PREFIX*filecache` `file`, '.
725
+			'`*PREFIX*vcategory_to_object` `tagmap`, '.
726
+			'`*PREFIX*vcategory` `tag` '.
727 727
 			// JOIN filecache to vcategory_to_object
728
-			'WHERE `file`.`fileid` = `tagmap`.`objid` ' .
728
+			'WHERE `file`.`fileid` = `tagmap`.`objid` '.
729 729
 			// JOIN vcategory_to_object to vcategory
730
-			'AND `tagmap`.`type` = `tag`.`type` ' .
731
-			'AND `tagmap`.`categoryid` = `tag`.`id` ' .
730
+			'AND `tagmap`.`type` = `tag`.`type` '.
731
+			'AND `tagmap`.`categoryid` = `tag`.`id` '.
732 732
 			// conditions
733
-			'AND `file`.`storage` = ? ' .
734
-			'AND `tag`.`type` = \'files\' ' .
733
+			'AND `file`.`storage` = ? '.
734
+			'AND `tag`.`type` = \'files\' '.
735 735
 			'AND `tag`.`uid` = ? ';
736 736
 		if (is_int($tag)) {
737 737
 			$sql .= 'AND `tag`.`id` = ? ';
@@ -749,7 +749,7 @@  discard block
 block discarded – undo
749 749
 
750 750
 		$files = $result->fetchAll();
751 751
 
752
-		return array_map(function (array $data) {
752
+		return array_map(function(array $data) {
753 753
 			return self::cacheEntryFromData($data, $this->mimetypeLoader);
754 754
 		}, $files);
755 755
 	}
@@ -785,8 +785,8 @@  discard block
 block discarded – undo
785 785
 		}
786 786
 		if (isset($entry['mimetype']) && $entry['mimetype'] === 'httpd/unix-directory') {
787 787
 			$id = $entry['fileid'];
788
-			$sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 ' .
789
-				'FROM `*PREFIX*filecache` ' .
788
+			$sql = 'SELECT SUM(`size`) AS f1, MIN(`size`) AS f2 '.
789
+				'FROM `*PREFIX*filecache` '.
790 790
 				'WHERE `parent` = ? AND `storage` = ?';
791 791
 			$result = $this->connection->executeQuery($sql, array($id, $this->getNumericStorageId()));
792 792
 			if ($row = $result->fetch()) {
Please login to merge, or discard this patch.