Passed
Push — feature/909_Ampache_API_improv... ( a8b3f6...35a5ba )
by Pauli
02:38
created

AlbumMapper::advFormatSqlCondition()   D

Complexity

Conditions 24
Paths 24

Size

Total Lines 29
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 24
eloc 24
c 0
b 0
f 0
nc 24
nop 2
dl 0
loc 29
rs 4.1666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 OCA\Music\Utility\Util;
18
19
use OCP\IDBConnection;
20
21
/**
22
 * Type hint a base class methdo to help Scrutinizer
23
 * @method Album updateOrInsert(Album $album)
24
 * @phpstan-extends BaseMapper<Album>
25
 */
26
class AlbumMapper extends BaseMapper {
27
	public function __construct(IDBConnection $db) {
28
		parent::__construct($db, 'music_albums', Album::class, 'name');
29
	}
30
31
	/**
32
	 * Override the base implementation to include data from multiple tables
33
	 *
34
	 * {@inheritdoc}
35
	 * @see BaseMapper::selectEntities()
36
	 */
37
	protected function selectEntities(string $condition, string $extension=null) : string {
38
		return "SELECT `*PREFIX*music_albums`.*, `artist`.`name` AS `album_artist_name`
39
				FROM `*PREFIX*music_albums`
40
				INNER JOIN `*PREFIX*music_artists` `artist`
41
				ON `*PREFIX*music_albums`.`album_artist_id` = `artist`.`id`
42
				WHERE $condition $extension";
43
	}
44
45
	/**
46
	 * Overridden from \OCA\Music\Db\BaseMapper to add support for sorting by artist.
47
	 *
48
	 * {@inheritdoc}
49
	 * @see BaseMapper::formatSortingClause()
50
	 */
51
	protected function formatSortingClause(int $sortBy, bool $invertSort = false) : ?string {
52
		if ($sortBy === SortBy::Parent) {
53
			// Note: the alternative form "LOWER(`album_artist_name`) wouldn't work on PostgreSQL, see https://github.com/owncloud/music/issues/1046
54
			$dir = $invertSort ? 'DESC' : 'ASC';
55
			return "ORDER BY LOWER(`artist`.`name`) $dir, LOWER(`*PREFIX*music_albums`.`name`) $dir";
56
		} else {
57
			return parent::formatSortingClause($sortBy, $invertSort);
58
		}
59
	}
60
61
	/**
62
	 * Overridden from the base implementation to provide support for table-specific rules
63
	 *
64
	 * {@inheritdoc}
65
	 * @see BaseMapper::advFormatSqlCondition()
66
	 */
67
	protected function advFormatSqlCondition(string $rule, string $sqlOp) : string {
68
		// The extra subquery "mysqlhack" seen around some nested queries is needed in order for these to not be insanely slow on MySQL.
69
		// In case of 'recent_played', the MySQL 5.5.62 errored with "1235 This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'" without the extra subquery.
70
		switch ($rule) {
71
			case 'artist':			return "LOWER(`artist`.`name`) $sqlOp LOWER(?)";
72
			case 'song_artist':		return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*music_artists` `ar` ON `t`.`artist_id` = `ar`.`id` WHERE LOWER(`ar`.`name`) $sqlOp LOWER(?))";
73
			case 'song':			return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` WHERE LOWER(`t`.`title`) $sqlOp LOWER(?))";
74
			case 'year':			// fall through, we only have one kind of year
75
			case 'original_year':	return "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` GROUP BY `album_id` HAVING MIN(`year`) $sqlOp ?) mysqlhack)";
76
			case 'played_times':	return "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` from `*PREFIX*music_tracks` GROUP BY `album_id` HAVING SUM(`play_count`) $sqlOp ?) mysqlhack)";
77
			case 'last_play':		return "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` from `*PREFIX*music_tracks` GROUP BY `album_id` HAVING MAX(`last_played`) $sqlOp ?) mysqlhack)";
78
			case 'played':			// fall through, we give no access to other people's data
79
			case 'myplayed':		return "`*PREFIX*music_albums`.`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"
80
			case 'myplayedartist':	return "`album_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"
81
			case 'song_count':		return "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` GROUP BY `album_id` HAVING COUNT(`id`) $sqlOp ?) mysqlhack)";
82
			case 'time':			return "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` GROUP BY `album_id` HAVING SUM(`length`) $sqlOp ?) mysqlhack)";
83
			case 'genre':			// fall through, alias
84
			case 'album_genre':		return "`*PREFIX*music_albums`.`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
85
			case 'song_genre':		return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*music_genres` `g` ON `t`.`genre_id` = `g`.`id` WHERE LOWER(`g`.`name`) $sqlOp LOWER(?))";
86
			case 'no_genre':		return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*music_genres` `g` ON `t`.`genre_id` = `g`.`id` WHERE `g`.`name` " . (($sqlOp == 'IS NOT NULL') ? '=' : '!=') . ' "")';
87
			//case 'playlist':
88
			//case 'playlist_name':
89
			case 'file':			return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*filecache` `f` ON `t`.`file_id` = `f`.`fileid` WHERE LOWER(`f`.`name`) $sqlOp LOWER(?))";
90
			case 'recent_played':	return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM (SELECT `album_id`, MAX(`last_played`) FROM `*PREFIX*music_tracks` WHERE `user_id` = ? GROUP BY `album_id` ORDER BY MAX(`last_played`) DESC LIMIT $sqlOp) mysqlhack)";
91
			case 'mbid_album':		return parent::advFormatSqlCondition('mbid', $sqlOp); // alias
92
			case 'mbid_song':		return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` WHERE `t`.`mbid` $sqlOp ?)";
93
			case 'mbid_artist':		return "`artist`.`mbid` $sqlOp ?";
94
			case 'has_image':		return "`*PREFIX*music_albums`.`cover_file_id` $sqlOp"; // operator "IS NULL" or "IS NOT NULL"
95
			default:				return parent::advFormatSqlCondition($rule, $sqlOp);
96
		}
97
	}
98
99
	/**
100
	 * returns artist IDs mapped to album IDs
101
	 * does not include album_artist_id
102
	 *
103
	 * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given
104
	 * @param string $userId the user ID
105
	 * @return array int => int[], keys are albums IDs and values are arrays of artist IDs
106
	 */
107
	public function getPerformingArtistsByAlbumId(?array $albumIds, string $userId) : array {
108
		$sql = 'SELECT DISTINCT `track`.`album_id`, `track`.`artist_id`
109
				FROM `*PREFIX*music_tracks` `track`
110
				WHERE `track`.`user_id` = ? ';
111
		$params = [$userId];
112
113
		if ($albumIds !== null) {
0 ignored issues
show
introduced by
The condition $albumIds !== null is always true.
Loading history...
114
			$sql .= 'AND `track`.`album_id` IN ' . $this->questionMarks(\count($albumIds));
115
			$params = \array_merge($params, $albumIds);
116
		}
117
118
		$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

118
		$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...
119
		$artistIds = [];
120
		while ($row = $result->fetch()) {
121
			$artistIds[$row['album_id']][] = (int)$row['artist_id'];
122
		}
123
		return $artistIds;
124
	}
125
126
	/**
127
	 * returns release years mapped to album IDs
128
	 *
129
	 * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given
130
	 * @param string $userId the user ID
131
	 * @return array int => int[], keys are albums IDs and values are arrays of years
132
	 */
133
	public function getYearsByAlbumId(?array $albumIds, string $userId) : array {
134
		$sql = 'SELECT DISTINCT `track`.`album_id`, `track`.`year`
135
				FROM `*PREFIX*music_tracks` `track`
136
				WHERE `track`.`user_id` = ?
137
				AND `track`.`year` IS NOT NULL ';
138
		$params = [$userId];
139
140
		if ($albumIds !== null) {
0 ignored issues
show
introduced by
The condition $albumIds !== null is always true.
Loading history...
141
			$sql .= 'AND `track`.`album_id` IN ' . $this->questionMarks(\count($albumIds));
142
			$params = \array_merge($params, $albumIds);
143
		}
144
145
		$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

145
		$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...
146
		$years = [];
147
		while ($row = $result->fetch()) {
148
			$years[$row['album_id']][] = (int)$row['year'];
149
		}
150
		return $years;
151
	}
152
153
	/**
154
	 * returns genres mapped to album IDs
155
	 *
156
	 * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given
157
	 * @param string $userId the user ID
158
	 * @return array int => Genre[], keys are albums IDs and values are arrays of *partial* Genre objects (only id and name properties set)
159
	 */
160
	public function getGenresByAlbumId(?array $albumIds, string $userId) : array {
161
		$sql = 'SELECT DISTINCT `album_id`, `genre_id`, `*PREFIX*music_genres`.`name` AS `genre_name`
162
				FROM `*PREFIX*music_tracks`
163
				LEFT JOIN `*PREFIX*music_genres`
164
				ON `genre_id` = `*PREFIX*music_genres`.`id`
165
				WHERE `*PREFIX*music_tracks`.`user_id` = ?
166
				AND `genre_id` IS NOT NULL ';
167
		$params = [$userId];
168
169
		if ($albumIds !== null) {
0 ignored issues
show
introduced by
The condition $albumIds !== null is always true.
Loading history...
170
			$sql .= 'AND `album_id` IN ' . $this->questionMarks(\count($albumIds));
171
			$params = \array_merge($params, $albumIds);
172
		}
173
174
		$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

174
		$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...
175
		$genres = [];
176
		while ($row = $result->fetch()) {
177
			$genre = new Genre();
178
			$genre->setUserId($userId);
179
			$genre->setId((int)$row['genre_id']);
180
			$genre->setName($row['genre_name']);
181
			$genres[$row['album_id']][] = $genre;
182
		}
183
		return $genres;
184
	}
185
186
	/**
187
	 * returns number of disks per album ID
188
	 *
189
	 * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given
190
	 * @param string $userId the user ID
191
	 * @return array int => int, keys are albums IDs and values are disk counts
192
	 */
193
	public function getDiscCountByAlbumId(?array $albumIds, string $userId) : array {
194
		$sql = 'SELECT `album_id`, MAX(`disk`) AS `disc_count`
195
				FROM `*PREFIX*music_tracks`
196
				WHERE `user_id` = ?
197
				GROUP BY `album_id` ';
198
		$params = [$userId];
199
200
		if ($albumIds !== null) {
0 ignored issues
show
introduced by
The condition $albumIds !== null is always true.
Loading history...
201
			$sql .= 'HAVING `album_id` IN ' . $this->questionMarks(\count($albumIds));
202
			$params = \array_merge($params, $albumIds);
203
		}
204
205
		$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

205
		$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...
206
		$diskCountByAlbum = [];
207
		while ($row = $result->fetch()) {
208
			$diskCountByAlbum[$row['album_id']] = (int)$row['disc_count'];
209
		}
210
		return $diskCountByAlbum;
211
	}
212
213
	/**
214
	 * returns summed track play counts of each album of the user, omittig albums which have never been played
215
	 *
216
	 * @return array [int => int], keys are album IDs and values are play count sums; ordered largest counts first
217
	 */
218
	public function getAlbumTracksPlayCount(string $userId, ?int $limit=null, ?int $offset=null) : array {
219
		$sql = 'SELECT `album_id`, SUM(`play_count`) AS `sum_count`
220
				FROM `*PREFIX*music_tracks`
221
				WHERE `user_id` = ? AND `play_count` > 0
222
				GROUP BY `album_id`
223
				ORDER BY `sum_count` DESC, `album_id`'; // the second criterion is just to make the order predictable on even counts
224
225
		$result = $this->execute($sql, [$userId], $limit, $offset);
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

225
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($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...
226
		$playCountByAlbum = [];
227
		while ($row = $result->fetch()) {
228
			$playCountByAlbum[$row['album_id']] = (int)$row['sum_count'];
229
		}
230
		return $playCountByAlbum;
231
	}
232
233
	/**
234
	 * returns the latest play time of each album of the user, omittig albums which have never been played
235
	 *
236
	 * @return array [int => string], keys are album IDs and values are date-times; ordered latest times first
237
	 */
238
	public function getLatestAlbumPlayTimes(string $userId, ?int $limit=null, ?int $offset=null) : array {
239
		$sql = 'SELECT `album_id`, MAX(`last_played`) AS `latest_time`
240
				FROM `*PREFIX*music_tracks`
241
				WHERE `user_id` = ? AND `last_played` IS NOT NULL
242
				GROUP BY `album_id`
243
				ORDER BY `latest_time` DESC';
244
245
		$result = $this->execute($sql, [$userId], $limit, $offset);
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

245
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($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...
246
		$latestTimeByAlbum = [];
247
		while ($row = $result->fetch()) {
248
			$latestTimeByAlbum[$row['album_id']] = $row['latest_time'];
249
		}
250
		return $latestTimeByAlbum;
251
	}
252
253
	/**
254
	 * returns the latest play time of each album of the user, including albums which have never been played
255
	 *
256
	 * @return array [int => ?string], keys are album IDs and values are date-times (or null for never played);
257
	 *									ordered furthest times first
258
	 */
259
	public function getFurthestAlbumPlayTimes(string $userId, ?int $limit=null, ?int $offset=null) : array {
260
		$sql = 'SELECT `album_id`, MAX(`last_played`) AS `latest_time`
261
				FROM `*PREFIX*music_tracks`
262
				WHERE `user_id` = ?
263
				GROUP BY `album_id`
264
				ORDER BY `latest_time` ASC';
265
266
		$result = $this->execute($sql, [$userId], $limit, $offset);
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

266
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($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...
267
		$latestTimeByAlbum = [];
268
		while ($row = $result->fetch()) {
269
			$latestTimeByAlbum[$row['album_id']] = $row['latest_time'];
270
		}
271
		return $latestTimeByAlbum;
272
	}
273
274
	/**
275
	 * @return Album[]
276
	 */
277
	public function findAllByNameRecursive(string $name, string $userId, ?int $limit=null, ?int $offset=null) : array {
278
		$condition = '( LOWER(`artist`.`name`) LIKE LOWER(?) OR
279
						LOWER(`*PREFIX*music_albums`.`name`) LIKE LOWER(?) )';
280
		$sql = $this->selectUserEntities($condition, 'ORDER BY LOWER(`*PREFIX*music_albums`.`name`)');
281
		$name = BaseMapper::prepareSubstringSearchPattern($name);
282
		$params = [$userId, $name, $name];
283
		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

283
		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...
284
	}
285
286
	/**
287
	 * returns albums of a specified artist
288
	 * The artist may be an album_artist or the artist of a track
289
	 *
290
	 * @param integer $artistId ID of the artist
291
	 * @param string $userId the user ID
292
	 * @return Album[]
293
	 */
294
	public function findAllByArtist(int $artistId, string $userId, ?int $limit=null, ?int $offset=null) : array {
295
		$sql = $this->selectEntities(
296
				'`*PREFIX*music_albums`.`id` IN (
297
					SELECT DISTINCT `album`.`id`
298
					FROM `*PREFIX*music_albums` `album`
299
					WHERE `album`.`album_artist_id` = ?
300
						UNION
301
					SELECT DISTINCT `track`.`album_id`
302
					FROM `*PREFIX*music_tracks` `track`
303
					WHERE `track`.`artist_id` = ?
304
				) AND `*PREFIX*music_albums`.`user_id` = ?',
305
				'ORDER BY LOWER(`*PREFIX*music_albums`.`name`)');
306
		$params = [$artistId, $artistId, $userId];
307
		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

307
		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...
308
	}
309
310
	/**
311
	 * returns albums of a specified artist
312
	 * The artist must album_artist on the album, artists of individual tracks are not considered
313
	 *
314
	 * @param integer $artistId ID of the artist
315
	 * @param string $userId the user ID
316
	 * @return Album[]
317
	 */
318
	public function findAllByAlbumArtist(int $artistId, string $userId, ?int $limit=null, ?int $offset=null) : array {
319
		$sql = $this->selectUserEntities('`album_artist_id` = ?');
320
		$params = [$userId, $artistId];
321
		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

321
		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...
322
	}
323
324
	/**
325
	 * @return Album[]
326
	 */
327
	public function findAllByGenre(int $genreId, string $userId, int $limit=null, int $offset=null) : array {
328
		$sql = $this->selectUserEntities('EXISTS '.
329
				'(SELECT 1 FROM `*PREFIX*music_tracks` `track`
330
				  WHERE `*PREFIX*music_albums`.`id` = `track`.`album_id`
331
				  AND `track`.`genre_id` = ?)');
332
333
		$params = [$userId, $genreId];
334
		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

334
		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...
335
	}
336
337
	/**
338
	 * @return boolean True if one or more albums were influenced
339
	 */
340
	public function updateFolderCover(int $coverFileId, int $folderId) : bool {
341
		$sql = 'SELECT DISTINCT `tracks`.`album_id`
342
				FROM `*PREFIX*music_tracks` `tracks`
343
				JOIN `*PREFIX*filecache` `files` ON `tracks`.`file_id` = `files`.`fileid`
344
				WHERE `files`.`parent` = ?';
345
		$params = [$folderId];
346
		$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

346
		$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...
347
348
		$updated = false;
349
		if ($result->rowCount()) {
350
			$sql = 'UPDATE `*PREFIX*music_albums`
351
					SET `cover_file_id` = ?
352
					WHERE `cover_file_id` IS NULL AND `id` IN (?)';
353
			$params = [$coverFileId, \join(",", $result->fetchAll(\PDO::FETCH_COLUMN))];
354
			$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

354
			$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...
355
			$updated = $result->rowCount() > 0;
356
		}
357
358
		return $updated;
359
	}
360
361
	/**
362
	 * Set file ID to be used as cover for an album
363
	 */
364
	public function setCover(?int $coverFileId, int $albumId) : void {
365
		$sql = 'UPDATE `*PREFIX*music_albums`
366
				SET `cover_file_id` = ?
367
				WHERE `id` = ?';
368
		$params = [$coverFileId, $albumId];
369
		$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

369
		/** @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...
370
	}
371
372
	/**
373
	 * @param integer[] $coverFileIds
374
	 * @param string[]|null $userIds the users whose music library is targeted; all users are targeted if omitted
375
	 * @return Album[] albums which got modified (with incomplete data, only id and user are valid),
376
	 *         empty array if none
377
	 */
378
	public function removeCovers(array $coverFileIds, array $userIds=null) : array {
379
		// find albums using the given file as cover
380
		$sql = 'SELECT `id`, `user_id` FROM `*PREFIX*music_albums` WHERE `cover_file_id` IN ' .
381
			$this->questionMarks(\count($coverFileIds));
382
		$params = $coverFileIds;
383
		if ($userIds !== null) {
384
			$sql .= ' AND `user_id` IN ' . $this->questionMarks(\count($userIds));
385
			$params = \array_merge($params, $userIds);
386
		}
387
		$albums = $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

387
		$albums = /** @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...
388
389
		// if any albums found, remove the cover from those
390
		$count = \count($albums);
391
		if ($count) {
392
			$sql = 'UPDATE `*PREFIX*music_albums`
393
				SET `cover_file_id` = NULL
394
				WHERE `id` IN ' . $this->questionMarks($count);
395
			$params = Util::extractIds($albums);
396
			$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

396
			/** @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...
397
		}
398
399
		return $albums;
400
	}
401
402
	/**
403
	 * @param string|null $userId target user; omit to target all users
404
	 * @return array of dictionaries with keys [albumId, userId, parentFolderId]
405
	 */
406
	public function getAlbumsWithoutCover(string $userId = null) : array {
407
		$sql = 'SELECT DISTINCT `albums`.`id`, `albums`.`user_id`, `files`.`parent`
408
				FROM `*PREFIX*music_albums` `albums`
409
				JOIN `*PREFIX*music_tracks` `tracks` ON `albums`.`id` = `tracks`.`album_id`
410
				JOIN `*PREFIX*filecache` `files` ON `tracks`.`file_id` = `files`.`fileid`
411
				WHERE `albums`.`cover_file_id` IS NULL';
412
		$params = [];
413
		if ($userId !== null) {
414
			$sql .= ' AND `albums`.`user_id` = ?';
415
			$params[] = $userId;
416
		}
417
		$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

417
		$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...
418
		$return = [];
419
		while ($row = $result->fetch()) {
420
			$return[] = [
421
				'albumId' => (int)$row['id'],
422
				'userId' => $row['user_id'],
423
				'parentFolderId' => (int)$row['parent']
424
			];
425
		}
426
		return $return;
427
	}
428
429
	/**
430
	 * @return boolean True if a cover image was found and added for the album
431
	 */
432
	public function findAlbumCover(int $albumId, int $parentFolderId) : bool {
433
		$return = false;
434
		$imagesSql = 'SELECT `fileid`, `name`
435
					FROM `*PREFIX*filecache`
436
					JOIN `*PREFIX*mimetypes` ON `*PREFIX*mimetypes`.`id` = `*PREFIX*filecache`.`mimetype`
437
					WHERE `parent` = ? AND `*PREFIX*mimetypes`.`mimetype` LIKE \'image%\'';
438
		$params = [$parentFolderId];
439
		$result = $this->execute($imagesSql, $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

439
		$result = /** @scrutinizer ignore-deprecated */ $this->execute($imagesSql, $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...
440
		$images = $result->fetchAll();
441
		if (\count($images) > 0) {
442
			$getImageRank = function($imageName) {
443
				$coverNames = ['cover', 'albumart', 'album', 'front', 'folder'];
444
				foreach ($coverNames as $i => $coverName) {
445
					if (Util::startsWith($imageName, $coverName, /*$ignoreCase=*/true)) {
446
						return $i;
447
					}
448
				}
449
				return \count($coverNames);
450
			};
451
452
			\usort($images, function ($imageA, $imageB) use ($getImageRank) {
453
				return $getImageRank($imageA['name']) <=> $getImageRank($imageB['name']);
454
			});
455
			$imageId = (int)$images[0]['fileid'];
456
			$this->setCover($imageId, $albumId);
457
			$return = true;
458
		}
459
		return $return;
460
	}
461
462
	/**
463
	 * Given an array of track IDs, find corresponding uniqu album IDs, including only
464
	 * those album which have a cover art set.
465
	 * @param int[] $trackIds
466
	 * @return Album[]
467
	 */
468
	public function findAlbumsWithCoversForTracks(array $trackIds, string $userId, int $limit) : array {
469
		$sql = 'SELECT DISTINCT `albums`.*
470
				FROM `*PREFIX*music_albums` `albums`
471
				JOIN `*PREFIX*music_tracks` `tracks` ON `albums`.`id` = `tracks`.`album_id`
472
				WHERE `albums`.`cover_file_id` IS NOT NULL
473
				AND `albums`.`user_id` = ?
474
				AND `tracks`.`id` IN ' . $this->questionMarks(\count($trackIds));
475
		$params = \array_merge([$userId], $trackIds);
476
477
		return $this->findEntities($sql, $params, $limit);
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

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

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...
478
	}
479
480
	/**
481
	 * Returns the count of albums where the given Artist is featured in
482
	 * @param integer $artistId
483
	 * @return integer
484
	 */
485
	public function countByArtist(int $artistId) : int {
486
		$sql = 'SELECT COUNT(*) AS count FROM (
487
					SELECT DISTINCT `track`.`album_id`
488
					FROM `*PREFIX*music_tracks` `track`
489
					WHERE `track`.`artist_id` = ?
490
						UNION
491
					SELECT `album`.`id`
492
					FROM `*PREFIX*music_albums` `album`
493
					WHERE `album`.`album_artist_id` = ?
494
				) tmp';
495
		$params = [$artistId, $artistId];
496
		$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

496
		$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...
497
		$row = $result->fetch();
498
		return (int)$row['count'];
499
	}
500
501
	/**
502
	 * Returns the count of albums where the given artist is the album artist
503
	 * @param integer $artistId
504
	 * @return integer
505
	 */
506
	public function countByAlbumArtist(int $artistId) : int {
507
		$sql = 'SELECT COUNT(*) AS count
508
				FROM `*PREFIX*music_albums` `album`
509
				WHERE `album`.`album_artist_id` = ?';
510
		$params = [$artistId];
511
		$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

511
		$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...
512
		$row = $result->fetch();
513
		return (int)$row['count'];
514
	}
515
516
	/**
517
	 * @see \OCA\Music\Db\BaseMapper::findUniqueEntity()
518
	 * @param Album $album
519
	 * @return Album
520
	 */
521
	protected function findUniqueEntity(Entity $album) : Entity {
522
		$sql = $this->selectUserEntities('`*PREFIX*music_albums`.`hash` = ?');
523
		return $this->findEntity($sql, [$album->getUserId(), $album->getHash()]);
0 ignored issues
show
Bug introduced by
The method getHash() 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

523
		return $this->findEntity($sql, [$album->getUserId(), $album->/** @scrutinizer ignore-call */ getHash()]);
Loading history...
Bug Best Practice introduced by
The expression return $this->findEntity...(), $album->getHash())) returns the type OCP\AppFramework\Db\Entity which includes types incompatible with the type-hinted return OCA\Music\Db\Entity.
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

523
		return /** @scrutinizer ignore-deprecated */ $this->findEntity($sql, [$album->getUserId(), $album->getHash()]);

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...
524
	}
525
}
526