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

TrackMapper::mapGenreIdsToTrackIds()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 6
c 1
b 0
f 0
dl 0
loc 11
rs 10
cc 2
nc 2
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 'anywhere':		TODO 
79
			case 'album':			return "`album_id` IN (SELECT `id` from `*PREFIX*music_albums` `al` WHERE LOWER(`al`.`name`) $sqlOp LOWER(?))";
80
			case 'artist':			return "LOWER(`artist`.`name`) $sqlOp LOWER(?)";
81
			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(?))";
82
			case 'track':			return "`number` $sqlOp ?";
83
			case 'year':			return "`year` $sqlOp ?";
84
			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)";
85
			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)";
86
			case 'played_times':	return "`play_count` $sqlOp ?";
87
			case 'last_play':		return "`last_played` $sqlOp ?";
88
			case 'played':			// fall through, we give no access to other people's data
89
			case 'myplayed':		return "`last_played` $sqlOp"; // operator "IS NULL" or "IS NOT NULL"
90
			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"
91
			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"
92
			case 'time':			return "`length` $sqlOp ?";
93
			case 'genre':			// fall through
94
			case 'song_genre':		return "LOWER(`genre`.`name`) $sqlOp LOWER(?)";
95
			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
96
			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
97
			case 'no_genre':		return ($sqlOp == 'IS NOT NULL') ? '`genre`.`name` = ""' : '`genre`.`name` != ""';
98
			case 'playlist':		return "$sqlOp EXISTS (SELECT 1 from `*PREFIX*music_playlists` `p` WHERE `p`.`id` = ? AND `p`.`track_ids` LIKE CONCAT('%|',`*PREFIX*music_tracks`.`id`, '|%'))";
99
			case 'playlist_name':	return "EXISTS (SELECT 1 from `*PREFIX*music_playlists` `p` WHERE `p`.`name` $sqlOp ? AND `p`.`track_ids` LIKE CONCAT('%|',`*PREFIX*music_tracks`.`id`, '|%'))";
100
			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)";
101
			case 'file':			return "LOWER(`file`.`name`) $sqlOp LOWER(?)";
102
			case 'mbid_song':		return parent::advFormatSqlCondition('mbid', $sqlOp); // alias
103
			case 'mbid_album':		return "`album_id` IN (SELECT `id` from `*PREFIX*music_albums` `al` WHERE `al`.`mbid` $sqlOp ?)";
104
			case 'mbid_artist':		return "`artist`.`mbid` $sqlOp ?";
105
			default:				return parent::advFormatSqlCondition($rule, $sqlOp);
106
		}
107
	}
108
109
	/**
110
	 * Returns all tracks of the given artist (both album and track artists are considered)
111
	 * @return Track[]
112
	 */
113
	public function findAllByArtist(int $artistId, string $userId, ?int $limit=null, ?int $offset=null) : array {
114
		$sql = $this->selectUserEntities(
115
				'`artist_id` = ? OR `album_id` IN (SELECT `id` from `*PREFIX*music_albums` WHERE `album_artist_id` = ?) ',
116
				'ORDER BY LOWER(`title`)');
117
		$params = [$userId, $artistId, $artistId];
118
		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

118
		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...
119
	}
120
121
	/**
122
	 * @return Track[]
123
	 */
124
	public function findAllByAlbum(int $albumId, string $userId, ?int $artistId=null, ?int $limit=null, ?int $offset=null) : array {
125
		$condition = '`album_id` = ?';
126
		$params = [$userId, $albumId];
127
128
		if ($artistId !== null) {
129
			$condition .= ' AND `artist_id` = ? ';
130
			$params[] = $artistId;
131
		}
132
133
		$sql = $this->selectUserEntities($condition,
134
				'ORDER BY `*PREFIX*music_tracks`.`disk`, `number`, LOWER(`title`)');
135
		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

135
		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...
136
	}
137
138
	/**
139
	 * @return Track[]
140
	 */
141
	public function findAllByFolder(int $folderId, string $userId, ?int $limit=null, ?int $offset=null) : array {
142
		$sql = $this->selectUserEntities('`file`.`parent` = ?', 'ORDER BY LOWER(`title`)');
143
		$params = [$userId, $folderId];
144
		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

144
		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...
145
	}
146
147
	/**
148
	 * @return Track[]
149
	 */
150
	public function findAllByGenre(int $genreId, string $userId, ?int $limit=null, ?int $offset=null) : array {
151
		$sql = $this->selectUserEntities('`genre_id` = ?', 'ORDER BY LOWER(`title`)');
152
		$params = [$userId, $genreId];
153
		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

153
		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...
154
	}
155
156
	/**
157
	 * @param string $userId
158
	 * @return int[]
159
	 */
160
	public function findAllFileIds(string $userId) : array {
161
		$sql = 'SELECT `file_id` FROM `*PREFIX*music_tracks` WHERE `user_id` = ?';
162
		$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

162
		$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...
163
164
		return \array_map(function ($i) {
165
			return (int)$i['file_id'];
166
		}, $result->fetchAll());
167
	}
168
169
	/**
170
	 * Find a track of user matching a file ID
171
	 * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
172
	 */
173
	public function findByFileId(int $fileId, string $userId) : Track {
174
		$sql = $this->selectUserEntities('`file_id` = ?');
175
		$params = [$userId, $fileId];
176
		return $this->findEntity($sql, $params);
0 ignored issues
show
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

176
		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...
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...
177
	}
178
179
	/**
180
	 * Find tracks of user with multiple file IDs
181
	 * @param integer[] $fileIds
182
	 * @param string[] $userIds
183
	 * @return Track[]
184
	 */
185
	public function findByFileIds(array $fileIds, array $userIds) : array {
186
		$sql = $this->selectEntities(
187
				'`*PREFIX*music_tracks`.`user_id` IN ' . $this->questionMarks(\count($userIds)) .
188
				' AND `file_id` IN '. $this->questionMarks(\count($fileIds)));
189
		$params = \array_merge($userIds, $fileIds);
190
		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

190
		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...
191
	}
192
193
	/**
194
	 * Finds tracks of all users matching one or multiple file IDs
195
	 * @param integer[] $fileIds
196
	 * @return Track[]
197
	 */
198
	public function findAllByFileIds(array $fileIds) : array {
199
		$sql = $this->selectEntities('`file_id` IN '.
200
				$this->questionMarks(\count($fileIds)));
201
		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

201
		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...
202
	}
203
204
	public function countByArtist(int $artistId) : int {
205
		$sql = 'SELECT COUNT(*) AS `count` FROM `*PREFIX*music_tracks` WHERE `artist_id` = ?';
206
		$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

206
		$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...
207
		$row = $result->fetch();
208
		return (int)$row['count'];
209
	}
210
211
	public function countByAlbum(int $albumId) : int {
212
		$sql = 'SELECT COUNT(*) AS `count` FROM `*PREFIX*music_tracks` WHERE `album_id` = ?';
213
		$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

213
		$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...
214
		$row = $result->fetch();
215
		return (int)$row['count'];
216
	}
217
218
	/**
219
	 * @return integer Duration in seconds
220
	 */
221
	public function totalDurationOfAlbum(int $albumId) : int {
222
		$sql = 'SELECT SUM(`length`) AS `duration` FROM `*PREFIX*music_tracks` WHERE `album_id` = ?';
223
		$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

223
		$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...
224
		$row = $result->fetch();
225
		return (int)$row['duration'];
226
	}
227
228
	/**
229
	 * @return integer Duration in seconds
230
	 */
231
	public function totalDurationByArtist(int $artistId) : int {
232
		$sql = 'SELECT SUM(`length`) AS `duration` FROM `*PREFIX*music_tracks` WHERE `artist_id` = ?';
233
		$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

233
		$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...
234
		$row = $result->fetch();
235
		return (int)$row['duration'];
236
	}
237
238
	/**
239
	 * Get durations of the given tracks.
240
	 * @param integer[] $trackIds
241
	 * @return array {int => int} where keys are track IDs and values are corresponding durations
242
	 */
243
	public function getDurations(array $trackIds) : array {
244
		$result = [];
245
246
		if (!empty($trackIds)) {
247
			$sql = 'SELECT `id`, `length` FROM `*PREFIX*music_tracks` WHERE `id` IN ' .
248
						$this->questionMarks(\count($trackIds));
249
			$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

249
			$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...
250
			foreach ($rows as $row) {
251
				$result[$row['id']] = (int)$row['length'];
252
			}
253
		}
254
		return $result;
255
	}
256
257
	/**
258
	 * @return Track[]
259
	 */
260
	public function findAllByNameRecursive(string $name, string $userId, ?int $limit=null, ?int $offset=null) {
261
		$condition = '( LOWER(`artist`.`name`) LIKE LOWER(?) OR
262
						LOWER(`album`.`name`) LIKE LOWER(?) OR
263
						LOWER(`title`) LIKE LOWER(?) )';
264
		$sql = $this->selectUserEntities($condition, 'ORDER BY LOWER(`title`)');
265
		$name = BaseMapper::prepareSubstringSearchPattern($name);
266
		$params = [$userId, $name, $name, $name];
267
		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

267
		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...
268
	}
269
270
	/**
271
	 * Returns all tracks specified by name and/or artist name
272
	 * @param string|null $name the name of the track
273
	 * @param string|null $artistName the name of the artist
274
	 * @param string $userId the name of the user
275
	 * @return Track[] Tracks matching the criteria
276
	 */
277
	public function findAllByNameAndArtistName(?string $name, ?string $artistName, string $userId) : array {
278
		$sqlConditions = [];
279
		$params = [$userId];
280
281
		if (!empty($name)) {
282
			$sqlConditions[] = '`title` = ?';
283
			$params[] = $name;
284
		}
285
286
		if (!empty($artistName)) {
287
			$sqlConditions[] = '`artist`.`name` = ?';
288
			$params[] = $artistName;
289
		}
290
291
		// at least one condition has to be given, otherwise return an empty set
292
		if (\count($sqlConditions) > 0) {
293
			$sql = $this->selectUserEntities(\implode(' AND ', $sqlConditions));
294
			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

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

338
		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...
339
	}
340
341
	/**
342
	 * Find most frequently played tracks
343
	 * @return Track[]
344
	 */
345
	public function findFrequentPlay(string $userId, ?int $limit=null, ?int $offset=null) : array {
346
		$sql = $this->selectUserEntities('`play_count` > 0', 'ORDER BY `play_count` DESC, LOWER(`title`)');
347
		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

347
		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...
348
	}
349
350
	/**
351
	 * Find most recently played tracks
352
	 * @return Track[]
353
	 */
354
	public function findRecentPlay(string $userId, ?int $limit=null, ?int $offset=null) : array {
355
		$sql = $this->selectUserEntities('`last_played` IS NOT NULL', 'ORDER BY `last_played` DESC');
356
		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

356
		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...
357
	}
358
359
	/**
360
	 * Find least recently played tracks
361
	 * @return Track[]
362
	 */
363
	public function findNotRecentPlay(string $userId, ?int $limit=null, ?int $offset=null) : array {
364
		$sql = $this->selectUserEntities(null, 'ORDER BY `last_played` ASC');
365
		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

365
		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...
366
	}
367
368
	/**
369
	 * Finds all track IDs of the user along with the parent folder ID of each track
370
	 * @return array where keys are folder IDs and values are arrays of track IDs
371
	 */
372
	public function findTrackAndFolderIds(string $userId) : array {
373
		$sql = 'SELECT `track`.`id` AS id, `file`.`name` AS `filename`, `file`.`parent` AS parent
374
				FROM `*PREFIX*music_tracks` `track`
375
				JOIN `*PREFIX*filecache` `file`
376
				ON `track`.`file_id` = `file`.`fileid`
377
				WHERE `track`.`user_id` = ?';
378
379
		$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

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

414
			$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...
415
416
			foreach ($rows as $row) {
417
				$result[$row['fileid']] = [
418
					'name' => $row['name'],
419
					'parent' => (int)$row['parent']
420
				];
421
			}
422
		}
423
424
		return $result;
425
	}
426
427
	/**
428
	 * Returns all genre IDs associated with the given artist
429
	 * @return int[]
430
	 */
431
	public function getGenresByArtistId(int $artistId, string $userId) : array {
432
		$sql = 'SELECT DISTINCT(`genre_id`) FROM `*PREFIX*music_tracks` WHERE
433
				`genre_id` IS NOT NULL AND `user_id` = ? AND `artist_id` = ?';
434
		$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

434
		$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...
435
		return $rows->fetchAll(\PDO::FETCH_COLUMN);
436
	}
437
438
	/**
439
	 * Returns all tracks IDs of the user, organized by the genre_id.
440
	 * @return array where keys are genre IDs and values are arrays of track IDs
441
	 */
442
	public function mapGenreIdsToTrackIds(string $userId) : array {
443
		$sql = 'SELECT `id`, `genre_id` FROM `*PREFIX*music_tracks`
444
				WHERE `genre_id` IS NOT NULL and `user_id` = ?';
445
		$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

445
		$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...
446
447
		$result = [];
448
		foreach ($rows as $row) {
449
			$result[(int)$row['genre_id']][] = (int)$row['id'];
450
		}
451
452
		return $result;
453
	}
454
455
	/**
456
	 * Returns file IDs of the tracks which do not have genre scanned. This is not the same
457
	 * thing as unknown genre, which means that the genre has been scanned but was not found
458
	 * from the track metadata.
459
	 * @return int[]
460
	 */
461
	public function findFilesWithoutScannedGenre(string $userId) : array {
462
		$sql = 'SELECT `track`.`file_id` FROM `*PREFIX*music_tracks` `track`
463
				INNER JOIN `*PREFIX*filecache` `file`
464
				ON `track`.`file_id` = `file`.`fileid`
465
				WHERE `genre_id` IS NULL and `user_id` = ?';
466
		$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

466
		$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...
467
		return $rows->fetchAll(\PDO::FETCH_COLUMN);
468
	}
469
470
	/**
471
	 * Update "last played" timestamp and increment the total play count of the track.
472
	 * The DB row is updated *without* updating the `updated` column.
473
	 * @return bool true if the track was found and updated, false otherwise
474
	 */
475
	public function recordTrackPlayed(int $trackId, string $userId, \DateTime $timeOfPlay) : bool {
476
		$sql = 'UPDATE `*PREFIX*music_tracks`
477
				SET `last_played` = ?, `play_count` = `play_count` + 1
478
				WHERE `user_id` = ? AND `id` = ?';
479
		$params = [$timeOfPlay->format(BaseMapper::SQL_DATE_FORMAT), $userId, $trackId];
480
		$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

480
		$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...
481
		return ($result->rowCount() > 0);
482
	}
483
484
	/**
485
	 * @see \OCA\Music\Db\BaseMapper::findUniqueEntity()
486
	 * @param Track $track
487
	 * @return Track
488
	 */
489
	protected function findUniqueEntity(Entity $track) : Entity {
490
		return $this->findByFileId($track->getFileId(), $track->getUserId());
0 ignored issues
show
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

490
		return $this->findByFileId($track->/** @scrutinizer ignore-call */ getFileId(), $track->getUserId());
Loading history...
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

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