Passed
Push — feature/909_Ampache_API_improv... ( 10355f...63afeb )
by Pauli
14:47
created

AlbumMapper::advFormatSqlCondition()   B

Complexity

Conditions 11
Paths 11

Size

Total Lines 28
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 12
c 0
b 0
f 0
nc 11
nop 2
dl 0
loc 28
rs 7.3166

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
		switch ($rule) {
70
			case 'artist':			return "LOWER(`artist`.`name`) $sqlOp LOWER(?)";
71
			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(?))";
72
			case 'song':			return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` WHERE LOWER(`t`.`title`) $sqlOp LOWER(?))";
73
			//case 'year':
74
			//case 'original_year':
75
			//case 'played_times':
76
			//case 'last_play':
77
			//case 'myplayed':
78
			//case 'myplayedartist':
79
			case 'song_count':		return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` GROUP BY `album_id` HAVING COUNT(`id`) $sqlOp ?) mysqlhack)";
80
			case 'time':			return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` GROUP BY `album_id` HAVING SUM(`length`) $sqlOp ?) mysqlhack)";
81
			//case 'genre':
82
			//case 'album_genre':
83
			//case 'song_genre':
84
			//case 'no_genre':
85
			//case 'playlist':
86
			//case 'playlist_name':
87
			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(?))";
88
			//case 'recent_played':
89
			//case 'recent_added':
90
			case 'mbid_album':		return parent::advFormatSqlCondition('mbid', $sqlOp); // alias
91
			case 'mbid_song':		return "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` WHERE `t`.`mbid` $sqlOp ?)";
92
			case 'mbid_artist':		return "`artist`.`mbid` $sqlOp ?";
93
			case 'has_image':		return "`*PREFIX*music_albums`.`cover_file_id` $sqlOp"; // operator "IS NULL" or "IS NOT NULL"
94
			default:				return parent::advFormatSqlCondition($rule, $sqlOp);
95
		}
96
	}
97
98
	/**
99
	 * returns artist IDs mapped to album IDs
100
	 * does not include album_artist_id
101
	 *
102
	 * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given
103
	 * @param string $userId the user ID
104
	 * @return array int => int[], keys are albums IDs and values are arrays of artist IDs
105
	 */
106
	public function getPerformingArtistsByAlbumId(?array $albumIds, string $userId) : array {
107
		$sql = 'SELECT DISTINCT `track`.`album_id`, `track`.`artist_id`
108
				FROM `*PREFIX*music_tracks` `track`
109
				WHERE `track`.`user_id` = ? ';
110
		$params = [$userId];
111
112
		if ($albumIds !== null) {
0 ignored issues
show
introduced by
The condition $albumIds !== null is always true.
Loading history...
113
			$sql .= 'AND `track`.`album_id` IN ' . $this->questionMarks(\count($albumIds));
114
			$params = \array_merge($params, $albumIds);
115
		}
116
117
		$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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

522
		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

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