Passed
Push — master ( d05692...31284f )
by Pauli
02:01
created

TrackMapper::findAllByFolder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 1
eloc 3
c 2
b 1
f 0
nc 1
nop 2
dl 0
loc 4
ccs 0
cts 4
cp 0
crap 2
rs 10
1
<?php
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Morris Jobke <[email protected]>
10
 * @author Pauli Järvinen <[email protected]>
11
 * @copyright Morris Jobke 2013, 2014
12
 * @copyright Pauli Järvinen 2016 - 2020
13
 */
14
15
namespace OCA\Music\Db;
16
17
use OCP\IDBConnection;
0 ignored issues
show
Bug introduced by
The type OCP\IDBConnection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
19
class TrackMapper extends BaseMapper {
20
	public function __construct(IDBConnection $db) {
21
		parent::__construct($db, 'music_tracks', '\OCA\Music\Db\Track', 'title');
22
	}
23
24
	/**
25
	 * Override the base implementation
26
	 * @see \OCA\Music\Db\BaseMapper::selectEntities()
27
	 * @param string $condition
28
	 * @param string|null $extension
29
	 */
30
	protected function selectEntities($condition, $extension=null) {
31
		return "SELECT `track`.*, `file`.`name` AS `filename`, `file`.`size`
32
				FROM `*PREFIX*music_tracks` `track`
33
				INNER JOIN `*PREFIX*filecache` `file`
34
				ON `track`.`file_id` = `file`.`fileid`
35
				WHERE $condition $extension";
36
	}
37
38
	/**
39
	 * @param integer $artistId
40
	 * @param string $userId
41
	 * @return Track[]
42
	 */
43
	public function findAllByArtist($artistId, $userId) {
44
		$sql = $this->selectUserEntities('`artist_id` = ? ', 'ORDER BY LOWER(`track`.`title`)');
45
		$params = [$userId, $artistId];
46
		return $this->findEntities($sql, $params);
47
	}
48
49
	/**
50
	 * @param integer $albumId
51
	 * @param string $userId
52
	 * @param integer|null $artistId
53
	 * @return Track[]
54
	 */
55
	public function findAllByAlbum($albumId, $userId, $artistId = null) {
56
		$condition = '`track`.`album_id` = ?';
57
		$params = [$userId, $albumId];
58
59
		if ($artistId !== null) {
60
			$condition .= ' AND `track`.`artist_id` = ? ';
61
			$params[] = $artistId;
62
		}
63
64
		$sql = $this->selectUserEntities($condition, 
65
				'ORDER BY `track`.`disk`, `track`.`number`, LOWER(`track`.`title`)');
66
		return $this->findEntities($sql, $params);
67
	}
68
69
	/**
70
	 * @param integer $folderId
71
	 * @param string $userId
72
	 * @return Track[]
73
	 */
74
	public function findAllByFolder($folderId, $userId) {
75
		$sql = $this->selectUserEntities('`file`.`parent` = ?', 'ORDER BY LOWER(`track`.`title`)');
76
		$params = [$userId, $folderId];
77
		return $this->findEntities($sql, $params);
78
	}
79
80
	/**
81
	 * @param int $genreId
82
	 * @param string $userId
83
	 * @param int|null $limit
84
	 * @param int|null $offset
85
	 * @return Track[] tracks
86
	 */
87
	public function findAllByGenre($genreId, $userId, $limit=null, $offset=null) {
88
		$sql = $this->selectUserEntities('`genre_id` = ?', 'ORDER BY LOWER(`track`.`title`)');
89
		$params = [$userId, $genreId];
90
		return $this->findEntities($sql, $params, $limit, $offset);
91
	}
92
93
	/**
94
	 * @param string $userId
95
	 * @return int[]
96
	 */
97
	public function findAllFileIds($userId) {
98
		$sql = 'SELECT `file_id` FROM `*PREFIX*music_tracks` WHERE `user_id` = ?';
99
		$result = $this->execute($sql, [$userId]);
100
101
		return \array_map(function ($i) {
102
			return $i['file_id'];
103
		}, $result->fetchAll());
104
	}
105
106
	/**
107
	 * Find a track of user matching a file ID
108
	 * @param integer $fileId
109
	 * @param string $userId
110
	 * @return Track
111
	 * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
112
	 */
113
	public function findByFileId($fileId, $userId) {
114
		$sql = $this->selectUserEntities('`track`.`file_id` = ?');
115
		$params = [$userId, $fileId];
116
		return $this->findEntity($sql, $params);
117
	}
118
119
	/**
120
	 * Find tracks of user with multiple file IDs
121
	 * @param integer[] $fileIds
122
	 * @param string[] $userIds
123
	 * @return Track[]
124
	 */
125
	public function findByFileIds($fileIds, $userIds) {
126
		$sql = $this->selectEntities(
127
				'`track`.`user_id` IN ' . $this->questionMarks(\count($userIds)) .
128
				' AND `track`.`file_id` IN '. $this->questionMarks(\count($fileIds)));
129
		$params = \array_merge($userIds, $fileIds);
130
		return $this->findEntities($sql, $params);
131
	}
132
133
	/**
134
	 * Finds tracks of all users matching one or multiple file IDs
135
	 * @param integer[] $fileIds
136
	 * @return Track[]
137
	 */
138
	public function findAllByFileIds($fileIds) {
139
		$sql = $this->selectEntities('`track`.`file_id` IN '.
140
				$this->questionMarks(\count($fileIds)));
141
		return $this->findEntities($sql, $fileIds);
142
	}
143
144
	/**
145
	 * @param integer $artistId
146
	 * @return integer
147
	 */
148
	public function countByArtist($artistId) {
149
		$sql = 'SELECT COUNT(*) AS `count` FROM `*PREFIX*music_tracks` WHERE `artist_id` = ?';
150
		$result = $this->execute($sql, [$artistId]);
151
		$row = $result->fetch();
152
		return $row['count'];
153
	}
154
155
	/**
156
	 * @param integer $albumId
157
	 * @return integer
158
	 */
159
	public function countByAlbum($albumId) {
160
		$sql = 'SELECT COUNT(*) AS `count` FROM `*PREFIX*music_tracks` WHERE `album_id` = ?';
161
		$result = $this->execute($sql, [$albumId]);
162
		$row = $result->fetch();
163
		return $row['count'];
164
	}
165
166
	/**
167
	 * @param integer $albumId
168
	 * @return integer Duration in seconds
169
	 */
170
	public function totalDurationOfAlbum($albumId) {
171
		$sql = 'SELECT SUM(`length`) AS `duration` FROM `*PREFIX*music_tracks` WHERE `album_id` = ?';
172
		$result = $this->execute($sql, [$albumId]);
173
		$row = $result->fetch();
174
		return $row['duration'];
175
	}
176
177
	/**
178
	 * Get durations of the given tracks.
179
	 * @param integer[] $trackIds
180
	 * @return array {int => int} where keys are track IDs and values are corresponding durations
181
	 */
182
	public function getDurations($trackIds) {
183
		$result = [];
184
185
		if (!empty($trackIds)) {
186
			$sql = 'SELECT `id`, `length` FROM `*PREFIX*music_tracks` WHERE `id` IN ' .
187
						$this->questionMarks(\count($trackIds));
188
			$rows = $this->execute($sql, $trackIds)->fetchAll();
189
			foreach ($rows as $row) {
190
				$result[$row['id']] = $row['length'];
191
			}
192
		}
193
		return $result;
194
	}
195
196
	/**
197
	 * @param string $name
198
	 * @param string $userId
199
	 * @return Track[]
200
	 */
201
	public function findAllByNameRecursive($name, $userId) {
202
		$condition = '(`track`.`artist_id` IN (SELECT `id` FROM `*PREFIX*music_artists` WHERE LOWER(`name`) LIKE LOWER(?)) OR '.
203
						' `track`.`album_id` IN (SELECT `id` FROM `*PREFIX*music_albums` WHERE LOWER(`name`) LIKE LOWER(?)) OR '.
204
						' LOWER(`track`.`title`) LIKE LOWER(?) )';
205
		$sql = $this->selectUserEntities($condition, 'ORDER BY LOWER(`track`.`title`)');
206
		$name = '%' . $name . '%';
207
		$params = [$userId, $name, $name, $name];
208
		return $this->findEntities($sql, $params);
209
	}
210
211
	/**
212
	 * Returns all tracks specified by name and/or artist name
213
	 * @param string|null $name the name of the track
214
	 * @param string|null $artistName the name of the artist
215
	 * @param bool $fuzzy match names using case-insensitive substring search
216
	 * @param string $userId the name of the user
217
	 * @return \OCA\Music\Db\Track[] Tracks matching the criteria
218
	 */
219
	public function findAllByNameAndArtistName($name, $artistName, $fuzzy, $userId) {
220
		$sqlConditions = [];
221
		$params = [$userId];
222
223
		if (!empty($name)) {
224
			if ($fuzzy) {
225
				$sqlConditions[] = 'LOWER(`track`.`title`) LIKE LOWER(?)';
226
				$params[] = "%$name%";
227
			} else {
228
				$sqlConditions[] = '`track`.`title` = ?';
229
				$params[] = $name;
230
			}
231
		}
232
233
		if (!empty($artistName)) {
234
			if ($fuzzy) {
235
				$equality = 'LOWER(`name`) LIKE LOWER(?)';
236
				$params[] = "%$artistName%";
237
			} else {
238
				$equality = '`name` = ?';
239
				$params[] = $artistName;
240
			}
241
			$sqlConditions[] = "`track`.`artist_id` IN (SELECT `id` FROM `*PREFIX*music_artists` WHERE $equality)";
242
		}
243
244
		// at least one condition has to be given, otherwise return an empty set
245
		if (\count($sqlConditions) > 0) {
246
			$sql = $this->selectUserEntities(\implode(' AND ', $sqlConditions));
247
			return $this->findEntities($sql, $params);
248
		} else {
249
			return [];
250
		}
251
	}
252
253
	/**
254
	 * Finds all track IDs of the user along with the parent folder ID of each track
255
	 * @param string $userId
256
	 * @return array where keys are folder IDs and values are arrays of track IDs
257
	 */
258
	public function findTrackAndFolderIds($userId) {
259
		$sql = 'SELECT `track`.`id` AS id, `file`.`parent` AS parent '.
260
				'FROM `*PREFIX*music_tracks` `track` '.
261
				'JOIN `*PREFIX*filecache` `file` '.
262
				'ON `track`.`file_id` = `file`.`fileid` '.
263
				'WHERE `track`.`user_id` = ?';
264
265
		$rows = $this->execute($sql, [$userId])->fetchAll();
266
267
		$result = [];
268
		foreach ($rows as $row) {
269
			$result[$row['parent']][] = $row['id'];
270
		}
271
272
		return $result;
273
	}
274
275
	/**
276
	 * Find names and paths of the file system nodes with given IDs within the given storage
277
	 * @param int[] $nodeIds
278
	 * @param string $storageId
279
	 * @return array where keys are the node IDs and values are associative arrays
280
	 *         like { 'name' => string, 'path' => string };
281
	 */
282
	public function findNodeNamesAndPaths($nodeIds, $storageId) {
283
		$result = [];
284
285
		if (!empty($nodeIds)) {
286
			$sql = 'SELECT `fileid`, `name`, `path` '.
287
					'FROM `*PREFIX*filecache` `filecache` '.
288
					'JOIN `*PREFIX*storages` `storages` '.
289
					'ON `filecache`.`storage` = `storages`.`numeric_id` '.
290
					'WHERE `storages`.`id` = ? '.
291
					'AND `filecache`.`fileid` IN '. $this->questionMarks(\count($nodeIds));
292
293
			$rows = $this->execute($sql, \array_merge([$storageId], $nodeIds))->fetchAll();
294
295
			foreach ($rows as $row) {
296
				$result[$row['fileid']] = [
297
					'name' => $row['name'],
298
					'path' => $row['path']
299
				];
300
			}
301
		}
302
303
		return $result;
304
	}
305
306
	/**
307
	 * Returns all genre IDs associated with the given artist
308
	 * @param int $artistId
309
	 * @param string $userId
310
	 * @return int[]
311
	 */
312
	public function getGenresByArtistId($artistId, $userId) {
313
		$sql = 'SELECT DISTINCT(`genre_id`) FROM `*PREFIX*music_tracks` WHERE
314
				`genre_id` IS NOT NULL AND `user_id` = ? AND `artist_id` = ?';
315
		$rows = $this->execute($sql, [$userId, $artistId]);
316
		return $rows->fetchAll(\PDO::FETCH_COLUMN, 0);
317
	}
318
319
	/**
320
	 * Returns all tracks IDs of the user, organized by the genre_id.
321
	 * @param string $userId
322
	 * @return array where keys are genre IDs and values are arrays of track IDs
323
	 */
324
	public function mapGenreIdsToTrackIds($userId) {
325
		$sql = 'SELECT `id`, `genre_id` FROM `*PREFIX*music_tracks`
326
				WHERE `genre_id` IS NOT NULL and `user_id` = ?';
327
		$rows = $this->execute($sql, [$userId]);
328
329
		$result = [];
330
		foreach ($rows as $row) {
331
			$result[$row['genre_id']][] = $row['id'];
332
		}
333
334
		return $result;
335
	}
336
337
	/**
338
	 * Returns file IDs of the tracks which do not have genre scanned. This is not the same
339
	 * thing as unknown genre, which means that the genre has been scanned but was not found
340
	 * from the track metadata.
341
	 * @param string $userId
342
	 * @return int[]
343
	 */
344
	public function findFilesWithoutScannedGenre($userId) {
345
		$sql = 'SELECT `track`.`file_id` FROM `*PREFIX*music_tracks` `track`
346
				INNER JOIN `*PREFIX*filecache` `file`
347
				ON `track`.`file_id` = `file`.`fileid`
348
				WHERE `genre_id` IS NULL and `user_id` = ?';
349
		$rows = $this->execute($sql, [$userId]);
350
		return $rows->fetchAll(\PDO::FETCH_COLUMN, 0);
351
	}
352
353
	/**
354
	 * @see \OCA\Music\Db\BaseMapper::findUniqueEntity()
355
	 * @param Track $track
356
	 * @return Track
357
	 */
358
	protected function findUniqueEntity($track) {
359
		return $this->findByFileId($track->getFileId(), $track->getUserId());
360
	}
361
}
362