Passed
Pull Request — master (#1078)
by Pauli
05:40 queued 02:37
created

TrackMapper::countByAlbum()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 1
1
<?php declare(strict_types=1);
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 - 2023
13
 */
14
15
namespace OCA\Music\Db;
16
17
use OCP\IDBConnection;
18
19
/**
20
 * @phpstan-extends BaseMapper<Track>
21
 */
22
class TrackMapper extends BaseMapper {
23
	public function __construct(IDBConnection $db) {
24
		parent::__construct($db, 'music_tracks', Track::class, 'title');
25
	}
26
27
	/**
28
	 * Override the base implementation to include data from multiple tables
29
	 *
30
	 * {@inheritdoc}
31
	 * @see BaseMapper::selectEntities()
32
	 */
33
	protected function selectEntities(string $condition, string $extension=null) : string {
34
		return "SELECT `*PREFIX*music_tracks`.*, `file`.`name` AS `filename`, `file`.`size`, `file`.`mtime` AS `file_mod_time`,
35
						`album`.`name` AS `album_name`, `artist`.`name` AS `artist_name`, `genre`.`name` AS `genre_name`
36
				FROM `*PREFIX*music_tracks`
37
				INNER JOIN `*PREFIX*filecache` `file`
38
				ON `*PREFIX*music_tracks`.`file_id` = `file`.`fileid`
39
				INNER JOIN `*PREFIX*music_albums` `album`
40
				ON `*PREFIX*music_tracks`.`album_id` = `album`.`id`
41
				INNER JOIN `*PREFIX*music_artists` `artist`
42
				ON `*PREFIX*music_tracks`.`artist_id` = `artist`.`id`
43
				LEFT JOIN `*PREFIX*music_genres` `genre`
44
				ON `*PREFIX*music_tracks`.`genre_id` = `genre`.`id`
45
				WHERE $condition $extension";
46
	}
47
48
	/**
49
	 * Overridden from the base implementation to add support for sorting by artist, play_count, and last_played.
50
	 *
51
	 * {@inheritdoc}
52
	 * @see BaseMapper::formatSortingClause()
53
	 */
54
	protected function formatSortingClause(int $sortBy, bool $invertSort = false) : ?string {
55
		$dir = $invertSort ? 'DESC' : 'ASC';
56
		switch ($sortBy) {
57
			case SortBy::Parent:
58
				// Note: the alternative form "LOWER(`artist_name`) wouldn't work on PostgreSQL, see https://github.com/owncloud/music/issues/1046 for a similar case
59
				return "ORDER BY LOWER(`artist`.`name`) $dir, LOWER(`title`) $dir";
60
			case SortBy::PlayCount:
61
				return "ORDER BY LOWER(`play_count`) $dir";
62
			case SortBy::LastPlayed:
63
				return "ORDER BY LOWER(`last_played`) $dir";
64
			default:
65
				return parent::formatSortingClause($sortBy, $invertSort);
66
		}
67
	}
68
69
	/**
70
	 * Overridden from the base implementation to provide support for table-specific rules
71
	 *
72
	 * {@inheritdoc}
73
	 * @see BaseMapper::advFormatSqlCondition()
74
	 */
75
	protected function advFormatSqlCondition(string $rule, string $sqlOp) : string {
76
		// The extra subquery "mysqlhack" seen around some nested queries is needed in order for these to not be insanely slow on MySQL.
77
		switch ($rule) {
78
			case 'album':			return "`album_id` IN (SELECT `id` from `*PREFIX*music_albums` `al` WHERE LOWER(`al`.`name`) $sqlOp LOWER(?))";
79
			case 'artist':			return "LOWER(`artist`.`name`) $sqlOp LOWER(?)";
80
			case 'album_artist':	return "`album_id` IN (SELECT `al`.`id` from `*PREFIX*music_albums` `al` JOIN `*PREFIX*music_artists` `ar` ON `al`.`album_artist_id` = `ar`.`id` WHERE LOWER(`ar`.`name`) $sqlOp LOWER(?))";
81
			case 'track':			return "`number` $sqlOp ?";
82
			case 'year':			return "`year` $sqlOp ?";
83
			case 'favorite_album':	return "`album_id` IN (SELECT `id` from `*PREFIX*music_albums` `al` WHERE LOWER(`al`.`name`) $sqlOp LOWER(?) AND `al`.`starred` IS NOT NULL)";
84
			case 'favorite_artist':	return "`artist_id` IN (SELECT `id` from `*PREFIX*music_artists` `ar` WHERE LOWER(`ar`.`name`) $sqlOp LOWER(?) AND `ar`.`starred` IS NOT NULL)";
85
			case 'played_times':	return "`play_count` $sqlOp ?";
86
			case 'last_play':		return "`last_played` $sqlOp ?";
87
			case 'played':			// fall through, we give no access to other people's data
88
			case 'myplayed':		return "`last_played` $sqlOp"; // operator "IS NULL" or "IS NOT NULL"
89
			case 'myplayedalbum':	return "`album_id` IN (SELECT * FROM (SELECT `album_id` from `*PREFIX*music_tracks` GROUP BY `album_id` HAVING MAX(`last_played`) $sqlOp) mysqlhack)"; // operator "IS NULL" or "IS NOT NULL"
90
			case 'myplayedartist':	return "`artist_id` IN (SELECT * FROM (SELECT `artist_id` from `*PREFIX*music_tracks` GROUP BY `artist_id` HAVING MAX(`last_played`) $sqlOp) mysqlhack)"; // operator "IS NULL" or "IS NOT NULL"
91
			case 'time':			return "`length` $sqlOp ?";
92
			case 'genre':			// fall through
93
			case 'song_genre':		return "LOWER(`genre`.`name`) $sqlOp LOWER(?)";
94
			case 'album_genre':		return "`album_id` IN (SELECT * FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*music_genres` `g` ON `t`.`genre_id` = `g`.`id` GROUP BY `album_id` HAVING LOWER(GROUP_CONCAT(`g`.`name`)) $sqlOp LOWER(?)) mysqlhack)"; // GROUP_CONCAT not available on PostgreSQL
95
			case 'artist_genre':	return "`artist_id` IN (SELECT * FROM (SELECT `artist_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*music_genres` `g` ON `t`.`genre_id` = `g`.`id` GROUP BY `artist_id` HAVING LOWER(GROUP_CONCAT(`g`.`name`)) $sqlOp LOWER(?)) mysqlhack)"; // GROUP_CONCAT not available on PostgreSQL
96
			case 'no_genre':		return ($sqlOp == 'IS NOT NULL') ? '`genre`.`name` = ""' : '`genre`.`name` != ""';
97
			//case 'playlist':
98
			//case 'playlist_name':	TODO: pattern to match against playlist track_ids somethign like: ('%|' || CONVERT(varchar(10), `*PREFIX*music_tracks`.`id`) || '|%')
99
			case 'recent_played':	return "`*PREFIX*music_tracks`.`id` IN (SELECT * FROM (SELECT `id` FROM `*PREFIX*music_tracks` WHERE `user_id` = ? ORDER BY `last_played` DESC LIMIT $sqlOp) mysqlhack)";
100
			case 'file':			return "LOWER(`file`.`name`) $sqlOp LOWER(?)";
101
			case 'mbid_song':		return parent::advFormatSqlCondition('mbid', $sqlOp); // alias
102
			case 'mbid_album':		return "`album_id` IN (SELECT `id` from `*PREFIX*music_albums` `al` WHERE `al`.`mbid` $sqlOp ?)";
103
			case 'mbid_artist':		return "`artist`.`mbid` $sqlOp ?";
104
			default:				return parent::advFormatSqlCondition($rule, $sqlOp);
105
		}
106
	}
107
108
	/**
109
	 * Returns all tracks of the given artist (both album and track artists are considered)
110
	 * @return Track[]
111
	 */
112
	public function findAllByArtist(int $artistId, string $userId, ?int $limit=null, ?int $offset=null) : array {
113
		$sql = $this->selectUserEntities(
114
				'`artist_id` = ? OR `album_id` IN (SELECT `id` from `*PREFIX*music_albums` WHERE `album_artist_id` = ?) ',
115
				'ORDER BY LOWER(`title`)');
116
		$params = [$userId, $artistId, $artistId];
117
		return $this->findEntities($sql, $params, $limit, $offset);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

117
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, $params, $limit, $offset);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
118
	}
119
120
	/**
121
	 * @return Track[]
122
	 */
123
	public function findAllByAlbum(int $albumId, string $userId, ?int $artistId=null, ?int $limit=null, ?int $offset=null) : array {
124
		$condition = '`album_id` = ?';
125
		$params = [$userId, $albumId];
126
127
		if ($artistId !== null) {
128
			$condition .= ' AND `artist_id` = ? ';
129
			$params[] = $artistId;
130
		}
131
132
		$sql = $this->selectUserEntities($condition,
133
				'ORDER BY `*PREFIX*music_tracks`.`disk`, `number`, LOWER(`title`)');
134
		return $this->findEntities($sql, $params, $limit, $offset);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

134
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, $params, $limit, $offset);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
135
	}
136
137
	/**
138
	 * @return Track[]
139
	 */
140
	public function findAllByFolder(int $folderId, string $userId, ?int $limit=null, ?int $offset=null) : array {
141
		$sql = $this->selectUserEntities('`file`.`parent` = ?', 'ORDER BY LOWER(`title`)');
142
		$params = [$userId, $folderId];
143
		return $this->findEntities($sql, $params, $limit, $offset);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

143
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, $params, $limit, $offset);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
144
	}
145
146
	/**
147
	 * @return Track[]
148
	 */
149
	public function findAllByGenre(int $genreId, string $userId, ?int $limit=null, ?int $offset=null) : array {
150
		$sql = $this->selectUserEntities('`genre_id` = ?', 'ORDER BY LOWER(`title`)');
151
		$params = [$userId, $genreId];
152
		return $this->findEntities($sql, $params, $limit, $offset);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

152
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, $params, $limit, $offset);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
153
	}
154
155
	/**
156
	 * @param string $userId
157
	 * @return int[]
158
	 */
159
	public function findAllFileIds(string $userId) : array {
160
		$sql = 'SELECT `file_id` FROM `*PREFIX*music_tracks` WHERE `user_id` = ?';
161
		$result = $this->execute($sql, [$userId]);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

161
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($sql, [$userId]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
162
163
		return \array_map(function ($i) {
164
			return (int)$i['file_id'];
165
		}, $result->fetchAll());
166
	}
167
168
	/**
169
	 * Find a track of user matching a file ID
170
	 * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
171
	 */
172
	public function findByFileId(int $fileId, string $userId) : Track {
173
		$sql = $this->selectUserEntities('`file_id` = ?');
174
		$params = [$userId, $fileId];
175
		return $this->findEntity($sql, $params);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->findEntity($sql, $params) returns the type OCP\AppFramework\Db\Entity which includes types incompatible with the type-hinted return OCA\Music\Db\Track.
Loading history...
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...oudMapper::findEntity() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

175
		return /** @scrutinizer ignore-deprecated */ $this->findEntity($sql, $params);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
176
	}
177
178
	/**
179
	 * Find tracks of user with multiple file IDs
180
	 * @param integer[] $fileIds
181
	 * @param string[] $userIds
182
	 * @return Track[]
183
	 */
184
	public function findByFileIds(array $fileIds, array $userIds) : array {
185
		$sql = $this->selectEntities(
186
				'`*PREFIX*music_tracks`.`user_id` IN ' . $this->questionMarks(\count($userIds)) .
187
				' AND `file_id` IN '. $this->questionMarks(\count($fileIds)));
188
		$params = \array_merge($userIds, $fileIds);
189
		return $this->findEntities($sql, $params);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

189
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, $params);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
190
	}
191
192
	/**
193
	 * Finds tracks of all users matching one or multiple file IDs
194
	 * @param integer[] $fileIds
195
	 * @return Track[]
196
	 */
197
	public function findAllByFileIds(array $fileIds) : array {
198
		$sql = $this->selectEntities('`file_id` IN '.
199
				$this->questionMarks(\count($fileIds)));
200
		return $this->findEntities($sql, $fileIds);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

200
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, $fileIds);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
201
	}
202
203
	public function countByArtist(int $artistId) : int {
204
		$sql = 'SELECT COUNT(*) AS `count` FROM `*PREFIX*music_tracks` WHERE `artist_id` = ?';
205
		$result = $this->execute($sql, [$artistId]);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

205
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($sql, [$artistId]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
206
		$row = $result->fetch();
207
		return (int)$row['count'];
208
	}
209
210
	public function countByAlbum(int $albumId) : int {
211
		$sql = 'SELECT COUNT(*) AS `count` FROM `*PREFIX*music_tracks` WHERE `album_id` = ?';
212
		$result = $this->execute($sql, [$albumId]);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

212
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($sql, [$albumId]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
213
		$row = $result->fetch();
214
		return (int)$row['count'];
215
	}
216
217
	/**
218
	 * @return integer Duration in seconds
219
	 */
220
	public function totalDurationOfAlbum(int $albumId) : int {
221
		$sql = 'SELECT SUM(`length`) AS `duration` FROM `*PREFIX*music_tracks` WHERE `album_id` = ?';
222
		$result = $this->execute($sql, [$albumId]);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

222
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($sql, [$albumId]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
223
		$row = $result->fetch();
224
		return (int)$row['duration'];
225
	}
226
227
	/**
228
	 * @return integer Duration in seconds
229
	 */
230
	public function totalDurationByArtist(int $artistId) : int {
231
		$sql = 'SELECT SUM(`length`) AS `duration` FROM `*PREFIX*music_tracks` WHERE `artist_id` = ?';
232
		$result = $this->execute($sql, [$artistId]);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

232
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($sql, [$artistId]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
233
		$row = $result->fetch();
234
		return (int)$row['duration'];
235
	}
236
237
	/**
238
	 * Get durations of the given tracks.
239
	 * @param integer[] $trackIds
240
	 * @return array {int => int} where keys are track IDs and values are corresponding durations
241
	 */
242
	public function getDurations(array $trackIds) : array {
243
		$result = [];
244
245
		if (!empty($trackIds)) {
246
			$sql = 'SELECT `id`, `length` FROM `*PREFIX*music_tracks` WHERE `id` IN ' .
247
						$this->questionMarks(\count($trackIds));
248
			$rows = $this->execute($sql, $trackIds)->fetchAll();
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

248
			$rows = /** @scrutinizer ignore-deprecated */ $this->execute($sql, $trackIds)->fetchAll();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
249
			foreach ($rows as $row) {
250
				$result[$row['id']] = (int)$row['length'];
251
			}
252
		}
253
		return $result;
254
	}
255
256
	/**
257
	 * @return Track[]
258
	 */
259
	public function findAllByNameRecursive(string $name, string $userId, ?int $limit=null, ?int $offset=null) {
260
		$condition = '( LOWER(`artist`.`name`) LIKE LOWER(?) OR
261
						LOWER(`album`.`name`) LIKE LOWER(?) OR
262
						LOWER(`title`) LIKE LOWER(?) )';
263
		$sql = $this->selectUserEntities($condition, 'ORDER BY LOWER(`title`)');
264
		$name = BaseMapper::prepareSubstringSearchPattern($name);
265
		$params = [$userId, $name, $name, $name];
266
		return $this->findEntities($sql, $params, $limit, $offset);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

266
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, $params, $limit, $offset);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
267
	}
268
269
	/**
270
	 * Returns all tracks specified by name and/or artist name
271
	 * @param string|null $name the name of the track
272
	 * @param string|null $artistName the name of the artist
273
	 * @param string $userId the name of the user
274
	 * @return Track[] Tracks matching the criteria
275
	 */
276
	public function findAllByNameAndArtistName(?string $name, ?string $artistName, string $userId) : array {
277
		$sqlConditions = [];
278
		$params = [$userId];
279
280
		if (!empty($name)) {
281
			$sqlConditions[] = '`title` = ?';
282
			$params[] = $name;
283
		}
284
285
		if (!empty($artistName)) {
286
			$sqlConditions[] = '`artist`.`name` = ?';
287
			$params[] = $artistName;
288
		}
289
290
		// at least one condition has to be given, otherwise return an empty set
291
		if (\count($sqlConditions) > 0) {
292
			$sql = $this->selectUserEntities(\implode(' AND ', $sqlConditions));
293
			return $this->findEntities($sql, $params);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

293
			return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, $params);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
294
		} else {
295
			return [];
296
		}
297
	}
298
299
	/**
300
	 * Returns all tracks specified by various criteria, all of which are optional
301
	 * @param int[] $genres Array of genre IDs
302
	 * @param int[] $artists Array of artist IDs
303
	 * @param int|null $fromYear Earliest release year to include
304
	 * @param int|null $toYear Latest release year to include
305
	 * @param int $sortBy Sorting rule as defined in the class SortBy
306
	 * @param string $userId the name of the user
307
	 * @return Track[] Tracks matching the criteria
308
	 */
309
	public function findAllByCriteria(
310
			array $genres, array $artists, ?int $fromYear, ?int $toYear,
311
			int $sortBy, bool $invertSort, string $userId, ?int $limit=null, ?int $offset=null) : array {
312
313
		$sqlConditions = [];
314
		$params = [$userId];
315
316
		if (!empty($genres)) {
317
			$sqlConditions[] = '`genre_id` IN ' . $this->questionMarks(\count($genres));
318
			$params = \array_merge($params, $genres);
319
		}
320
321
		if (!empty($artists)) {
322
			$sqlConditions[] = '`artist_id` IN ' . $this->questionMarks(\count($artists));
323
			$params = \array_merge($params, $artists);
324
		}
325
326
		if (!empty($fromYear)) {
327
			$sqlConditions[] = '`year` >= ?';
328
			$params[] = $fromYear;
329
		}
330
331
		if (!empty($toYear)) {
332
			$sqlConditions[] = '`year` <= ?';
333
			$params[] = $toYear;
334
		}
335
336
		$sql = $this->selectUserEntities(\implode(' AND ', $sqlConditions), $this->formatSortingClause($sortBy, $invertSort));
337
		return $this->findEntities($sql, $params, $limit, $offset);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

337
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, $params, $limit, $offset);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
338
	}
339
340
	/**
341
	 * Find most frequently played tracks
342
	 * @return Track[]
343
	 */
344
	public function findFrequentPlay(string $userId, ?int $limit=null, ?int $offset=null) : array {
345
		$sql = $this->selectUserEntities('`play_count` > 0', 'ORDER BY `play_count` DESC, LOWER(`title`)');
346
		return $this->findEntities($sql, [$userId], $limit, $offset);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

346
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, [$userId], $limit, $offset);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
347
	}
348
349
	/**
350
	 * Find most recently played tracks
351
	 * @return Track[]
352
	 */
353
	public function findRecentPlay(string $userId, ?int $limit=null, ?int $offset=null) : array {
354
		$sql = $this->selectUserEntities('`last_played` IS NOT NULL', 'ORDER BY `last_played` DESC');
355
		return $this->findEntities($sql, [$userId], $limit, $offset);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

355
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, [$userId], $limit, $offset);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
356
	}
357
358
	/**
359
	 * Find least recently played tracks
360
	 * @return Track[]
361
	 */
362
	public function findNotRecentPlay(string $userId, ?int $limit=null, ?int $offset=null) : array {
363
		$sql = $this->selectUserEntities(null, 'ORDER BY `last_played` ASC');
364
		return $this->findEntities($sql, [$userId], $limit, $offset);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...dMapper::findEntities() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

364
		return /** @scrutinizer ignore-deprecated */ $this->findEntities($sql, [$userId], $limit, $offset);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
365
	}
366
367
	/**
368
	 * Finds all track IDs of the user along with the parent folder ID of each track
369
	 * @return array where keys are folder IDs and values are arrays of track IDs
370
	 */
371
	public function findTrackAndFolderIds(string $userId) : array {
372
		$sql = 'SELECT `track`.`id` AS id, `file`.`name` AS `filename`, `file`.`parent` AS parent
373
				FROM `*PREFIX*music_tracks` `track`
374
				JOIN `*PREFIX*filecache` `file`
375
				ON `track`.`file_id` = `file`.`fileid`
376
				WHERE `track`.`user_id` = ?';
377
378
		$rows = $this->execute($sql, [$userId])->fetchAll();
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

378
		$rows = /** @scrutinizer ignore-deprecated */ $this->execute($sql, [$userId])->fetchAll();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
379
380
		// Sort the results according the file names. This can't be made using ORDERBY in the
381
		// SQL query because then we couldn't use the "natural order" comparison algorithm
382
		\usort($rows, function ($a, $b) {
383
			return \strnatcasecmp($a['filename'], $b['filename']);
384
		});
385
386
		// group the files to parent folder "buckets"
387
		$result = [];
388
		foreach ($rows as $row) {
389
			$result[(int)$row['parent']][] = (int)$row['id'];
390
		}
391
392
		return $result;
393
	}
394
395
	/**
396
	 * Find names and parents of the file system nodes with given IDs within the given storage
397
	 * @param int[] $nodeIds
398
	 * @param string $storageId
399
	 * @return array where keys are the node IDs and values are associative arrays
400
	 *         like { 'name' => string, 'parent' => int };
401
	 */
402
	public function findNodeNamesAndParents(array $nodeIds, string $storageId) : array {
403
		$result = [];
404
405
		if (!empty($nodeIds)) {
406
			$sql = 'SELECT `fileid`, `name`, `parent` '.
407
					'FROM `*PREFIX*filecache` `filecache` '.
408
					'JOIN `*PREFIX*storages` `storages` '.
409
					'ON `filecache`.`storage` = `storages`.`numeric_id` '.
410
					'WHERE `storages`.`id` = ? '.
411
					'AND `filecache`.`fileid` IN '. $this->questionMarks(\count($nodeIds));
412
413
			$rows = $this->execute($sql, \array_merge([$storageId], $nodeIds))->fetchAll();
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

413
			$rows = /** @scrutinizer ignore-deprecated */ $this->execute($sql, \array_merge([$storageId], $nodeIds))->fetchAll();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
414
415
			foreach ($rows as $row) {
416
				$result[$row['fileid']] = [
417
					'name' => $row['name'],
418
					'parent' => (int)$row['parent']
419
				];
420
			}
421
		}
422
423
		return $result;
424
	}
425
426
	/**
427
	 * Returns all genre IDs associated with the given artist
428
	 * @return int[]
429
	 */
430
	public function getGenresByArtistId(int $artistId, string $userId) : array {
431
		$sql = 'SELECT DISTINCT(`genre_id`) FROM `*PREFIX*music_tracks` WHERE
432
				`genre_id` IS NOT NULL AND `user_id` = ? AND `artist_id` = ?';
433
		$rows = $this->execute($sql, [$userId, $artistId]);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

433
		$rows = /** @scrutinizer ignore-deprecated */ $this->execute($sql, [$userId, $artistId]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
434
		return $rows->fetchAll(\PDO::FETCH_COLUMN);
435
	}
436
437
	/**
438
	 * Returns all tracks IDs of the user, organized by the genre_id.
439
	 * @return array where keys are genre IDs and values are arrays of track IDs
440
	 */
441
	public function mapGenreIdsToTrackIds(string $userId) : array {
442
		$sql = 'SELECT `id`, `genre_id` FROM `*PREFIX*music_tracks`
443
				WHERE `genre_id` IS NOT NULL and `user_id` = ?';
444
		$rows = $this->execute($sql, [$userId])->fetchAll();
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

444
		$rows = /** @scrutinizer ignore-deprecated */ $this->execute($sql, [$userId])->fetchAll();

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
445
446
		$result = [];
447
		foreach ($rows as $row) {
448
			$result[(int)$row['genre_id']][] = (int)$row['id'];
449
		}
450
451
		return $result;
452
	}
453
454
	/**
455
	 * Returns file IDs of the tracks which do not have genre scanned. This is not the same
456
	 * thing as unknown genre, which means that the genre has been scanned but was not found
457
	 * from the track metadata.
458
	 * @return int[]
459
	 */
460
	public function findFilesWithoutScannedGenre(string $userId) : array {
461
		$sql = 'SELECT `track`.`file_id` FROM `*PREFIX*music_tracks` `track`
462
				INNER JOIN `*PREFIX*filecache` `file`
463
				ON `track`.`file_id` = `file`.`fileid`
464
				WHERE `genre_id` IS NULL and `user_id` = ?';
465
		$rows = $this->execute($sql, [$userId]);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

465
		$rows = /** @scrutinizer ignore-deprecated */ $this->execute($sql, [$userId]);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
466
		return $rows->fetchAll(\PDO::FETCH_COLUMN);
467
	}
468
469
	/**
470
	 * Update "last played" timestamp and increment the total play count of the track.
471
	 * The DB row is updated *without* updating the `updated` column.
472
	 * @return bool true if the track was found and updated, false otherwise
473
	 */
474
	public function recordTrackPlayed(int $trackId, string $userId, \DateTime $timeOfPlay) : bool {
475
		$sql = 'UPDATE `*PREFIX*music_tracks`
476
				SET `last_played` = ?, `play_count` = `play_count` + 1
477
				WHERE `user_id` = ? AND `id` = ?';
478
		$params = [$timeOfPlay->format(BaseMapper::SQL_DATE_FORMAT), $userId, $trackId];
479
		$result = $this->execute($sql, $params);
0 ignored issues
show
Deprecated Code introduced by
The function OCA\Music\AppFramework\D...tcloudMapper::execute() has been deprecated: 14.0.0 Move over to QBMapper ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

479
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($sql, $params);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
480
		return ($result->rowCount() > 0);
481
	}
482
483
	/**
484
	 * @see \OCA\Music\Db\BaseMapper::findUniqueEntity()
485
	 * @param Track $track
486
	 * @return Track
487
	 */
488
	protected function findUniqueEntity(Entity $track) : Entity {
489
		return $this->findByFileId($track->getFileId(), $track->getUserId());
0 ignored issues
show
Bug introduced by
It seems like $track->getFileId() can also be of type null; however, parameter $fileId of OCA\Music\Db\TrackMapper::findByFileId() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

489
		return $this->findByFileId(/** @scrutinizer ignore-type */ $track->getFileId(), $track->getUserId());
Loading history...
Bug introduced by
The method getFileId() does not exist on OCA\Music\Db\Entity. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

489
		return $this->findByFileId($track->/** @scrutinizer ignore-call */ getFileId(), $track->getUserId());
Loading history...
490
	}
491
}
492