Passed
Push — master ( 511b17...8295e0 )
by Pauli
01:59
created

TrackMapper   A

Complexity

Total Complexity 31

Size/Duplication

Total Lines 322
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 12
Bugs 1 Features 0
Metric Value
eloc 115
c 12
b 1
f 0
dl 0
loc 322
ccs 0
cts 121
cp 0
rs 9.92
wmc 31

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A findAllByFolder() 0 4 1
A selectEntities() 0 6 1
A findAllByAlbum() 0 12 2
A findAllByArtist() 0 4 1
A findByFileId() 0 4 1
A findAllByGenre() 0 4 1
A findAllByFileIds() 0 4 1
A findAllFileIds() 0 7 1
A findByFileIds() 0 6 1
A findNodeNamesAndPaths() 0 22 3
A mapGenreIdsToTrackIds() 0 11 2
A findTrackAndFolderIds() 0 15 2
A countByAlbum() 0 5 1
A findUniqueEntity() 0 2 1
A findAllByNameRecursive() 0 8 1
A totalDurationOfAlbum() 0 5 1
B findAllByNameAndArtistName() 0 31 6
A findFilesWithoutScannedGenre() 0 7 1
A getGenresByArtistId() 0 5 1
A countByArtist() 0 5 1
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
	 * @param string $name
179
	 * @param string $userId
180
	 * @return Track[]
181
	 */
182
	public function findAllByNameRecursive($name, $userId) {
183
		$condition = '(`track`.`artist_id` IN (SELECT `id` FROM `*PREFIX*music_artists` WHERE LOWER(`name`) LIKE LOWER(?)) OR '.
184
						' `track`.`album_id` IN (SELECT `id` FROM `*PREFIX*music_albums` WHERE LOWER(`name`) LIKE LOWER(?)) OR '.
185
						' LOWER(`track`.`title`) LIKE LOWER(?) )';
186
		$sql = $this->selectUserEntities($condition, 'ORDER BY LOWER(`track`.`title`)');
187
		$name = '%' . $name . '%';
188
		$params = [$userId, $name, $name, $name];
189
		return $this->findEntities($sql, $params);
190
	}
191
192
	/**
193
	 * Returns all tracks specified by name and/or artist name
194
	 * @param string|null $name the name of the track
195
	 * @param string|null $artistName the name of the artist
196
	 * @param bool $fuzzy match names using case-insensitive substring search
197
	 * @param string $userId the name of the user
198
	 * @return \OCA\Music\Db\Track[] Tracks matching the criteria
199
	 */
200
	public function findAllByNameAndArtistName($name, $artistName, $fuzzy, $userId) {
201
		$sqlConditions = [];
202
		$params = [$userId];
203
204
		if (!empty($name)) {
205
			if ($fuzzy) {
206
				$sqlConditions[] = 'LOWER(`track`.`title`) LIKE LOWER(?)';
207
				$params[] = "%$name%";
208
			} else {
209
				$sqlConditions[] = '`track`.`title` = ?';
210
				$params[] = $name;
211
			}
212
		}
213
214
		if (!empty($artistName)) {
215
			if ($fuzzy) {
216
				$equality = 'LOWER(`name`) LIKE LOWER(?)';
217
				$params[] = "%$artistName%";
218
			} else {
219
				$equality = '`name` = ?';
220
				$params[] = $artistName;
221
			}
222
			$sqlConditions[] = "`track`.`artist_id` IN (SELECT `id` FROM `*PREFIX*music_artists` WHERE $equality)";
223
		}
224
225
		// at least one condition has to be given, otherwise return an empty set
226
		if (\count($sqlConditions) > 0) {
227
			$sql = $this->selectUserEntities(\implode(' AND ', $sqlConditions));
228
			return $this->findEntities($sql, $params);
229
		} else {
230
			return [];
231
		}
232
	}
233
234
	/**
235
	 * Finds all track IDs of the user along with the parent folder ID of each track
236
	 * @param string $userId
237
	 * @return array where keys are folder IDs and values are arrays of track IDs
238
	 */
239
	public function findTrackAndFolderIds($userId) {
240
		$sql = 'SELECT `track`.`id` AS id, `file`.`parent` AS parent '.
241
				'FROM `*PREFIX*music_tracks` `track` '.
242
				'JOIN `*PREFIX*filecache` `file` '.
243
				'ON `track`.`file_id` = `file`.`fileid` '.
244
				'WHERE `track`.`user_id` = ?';
245
246
		$rows = $this->execute($sql, [$userId])->fetchAll();
247
248
		$result = [];
249
		foreach ($rows as $row) {
250
			$result[$row['parent']][] = $row['id'];
251
		}
252
253
		return $result;
254
	}
255
256
	/**
257
	 * Find names and paths of the file system nodes with given IDs within the given storage
258
	 * @param int[] $nodeIds
259
	 * @param string $storageId
260
	 * @return array where keys are the node IDs and values are associative arrays
261
	 *         like { 'name' => string, 'path' => string };
262
	 */
263
	public function findNodeNamesAndPaths($nodeIds, $storageId) {
264
		$result = [];
265
266
		if (!empty($nodeIds)) {
267
			$sql = 'SELECT `fileid`, `name`, `path` '.
268
					'FROM `*PREFIX*filecache` `filecache` '.
269
					'JOIN `*PREFIX*storages` `storages` '.
270
					'ON `filecache`.`storage` = `storages`.`numeric_id` '.
271
					'WHERE `storages`.`id` = ? '.
272
					'AND `filecache`.`fileid` IN '. $this->questionMarks(\count($nodeIds));
273
274
			$rows = $this->execute($sql, \array_merge([$storageId], $nodeIds))->fetchAll();
275
276
			foreach ($rows as $row) {
277
				$result[$row['fileid']] = [
278
					'name' => $row['name'],
279
					'path' => $row['path']
280
				];
281
			}
282
		}
283
284
		return $result;
285
	}
286
287
	/**
288
	 * Returns all genre IDs associated with the given artist
289
	 * @param int $artistId
290
	 * @param string $userId
291
	 * @return int[]
292
	 */
293
	public function getGenresByArtistId($artistId, $userId) {
294
		$sql = 'SELECT DISTINCT(`genre_id`) FROM `*PREFIX*music_tracks` WHERE
295
				`genre_id` IS NOT NULL AND `user_id` = ? AND `artist_id` = ?';
296
		$rows = $this->execute($sql, [$userId, $artistId]);
297
		return $rows->fetchAll(\PDO::FETCH_COLUMN, 0);
298
	}
299
300
	/**
301
	 * Returns all tracks IDs of the user, organized by the genre_id.
302
	 * @param string $userId
303
	 * @return array where keys are genre IDs and values are arrays of track IDs
304
	 */
305
	public function mapGenreIdsToTrackIds($userId) {
306
		$sql = 'SELECT `id`, `genre_id` FROM `*PREFIX*music_tracks`
307
				WHERE `genre_id` IS NOT NULL and `user_id` = ?';
308
		$rows = $this->execute($sql, [$userId]);
309
310
		$result = [];
311
		foreach ($rows as $row) {
312
			$result[$row['genre_id']][] = $row['id'];
313
		}
314
315
		return $result;
316
	}
317
318
	/**
319
	 * Returns file IDs of the tracks which do not have genre scanned. This is not the same
320
	 * thing as unknown genre, which means that the genre has been scanned but was not found
321
	 * from the track metadata.
322
	 * @param string $userId
323
	 * @return int[]
324
	 */
325
	public function findFilesWithoutScannedGenre($userId) {
326
		$sql = 'SELECT `track`.`file_id` FROM `*PREFIX*music_tracks` `track`
327
				INNER JOIN `*PREFIX*filecache` `file`
328
				ON `track`.`file_id` = `file`.`fileid`
329
				WHERE `genre_id` IS NULL and `user_id` = ?';
330
		$rows = $this->execute($sql, [$userId]);
331
		return $rows->fetchAll(\PDO::FETCH_COLUMN, 0);
332
	}
333
334
	/**
335
	 * @see \OCA\Music\Db\BaseMapper::findUniqueEntity()
336
	 * @param Track $track
337
	 * @return Track
338
	 */
339
	protected function findUniqueEntity($track) {
340
		return $this->findByFileId($track->getFileId(), $track->getUserId());
341
	}
342
}
343