Passed
Push — master ( 860f03...511b17 )
by Pauli
02:01
created

AlbumMapper::findAll()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 4
dl 0
loc 11
ccs 0
cts 6
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Morris Jobke <[email protected]>
10
 * @author Pauli Järvinen <[email protected]>
11
 * @copyright Morris Jobke 2013, 2014
12
 * @copyright Pauli Järvinen 2016 - 2020
13
 */
14
15
namespace OCA\Music\Db;
16
17
use \OCA\Music\Utility\Util;
18
19
use OCP\IDBConnection;
0 ignored issues
show
Bug introduced by
The type OCP\IDBConnection was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
21
class AlbumMapper extends BaseMapper {
22
	public function __construct(IDBConnection $db) {
23
		parent::__construct($db, 'music_albums', '\OCA\Music\Db\Album', 'name');
24
	}
25
26
	/**
27
	 * returns artist IDs mapped to album IDs
28
	 * does not include album_artist_id
29
	 *
30
	 * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given
31
	 * @param string $userId the user ID
32
	 * @return array int => int[], keys are albums IDs and values are arrays of artist IDs
33
	 */
34
	public function getPerformingArtistsByAlbumId($albumIds, $userId) {
35
		$sql = 'SELECT DISTINCT `track`.`album_id`, `track`.`artist_id`
36
				FROM `*PREFIX*music_tracks` `track`
37
				WHERE `track`.`user_id` = ? ';
38
		$params = [$userId];
39
40
		if ($albumIds !== null) {
41
			$sql .= 'AND `track`.`album_id` IN ' . $this->questionMarks(\count($albumIds));
42
			$params = \array_merge($params, $albumIds);
43
		}
44
45
		$result = $this->execute($sql, $params);
46
		return $result->fetchAll(\PDO::FETCH_COLUMN|\PDO::FETCH_GROUP);
47
	}
48
49
	/**
50
	 * returns release years mapped to album IDs
51
	 *
52
	 * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given
53
	 * @param string $userId the user ID
54
	 * @return array int => int[], keys are albums IDs and values are arrays of years
55
	 */
56
	public function getYearsByAlbumId($albumIds, $userId) {
57
		$sql = 'SELECT DISTINCT `track`.`album_id`, `track`.`year`
58
				FROM `*PREFIX*music_tracks` `track`
59
				WHERE `track`.`user_id` = ?
60
				AND `track`.`year` IS NOT NULL ';
61
		$params = [$userId];
62
63
		if ($albumIds !== null) {
64
			$sql .= 'AND `track`.`album_id` IN ' . $this->questionMarks(\count($albumIds));
65
			$params = \array_merge($params, $albumIds);
66
		}
67
68
		$result = $this->execute($sql, $params);
69
		return $result->fetchAll(\PDO::FETCH_COLUMN|\PDO::FETCH_GROUP);
70
	}
71
72
	/**
73
	 * returns genres mapped to album IDs
74
	 *
75
	 * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given
76
	 * @param string $userId the user ID
77
	 * @return array int => string[], keys are albums IDs and values are arrays of genres
78
	 */
79
	public function getGenresByAlbumId($albumIds, $userId) {
80
		$sql = 'SELECT DISTINCT `album_id`, `genre_id`
81
				FROM `*PREFIX*music_tracks`
82
				WHERE `user_id` = ?
83
				AND `genre_id` IS NOT NULL ';
84
		$params = [$userId];
85
86
		if ($albumIds !== null) {
87
			$sql .= 'AND `album_id` IN ' . $this->questionMarks(\count($albumIds));
88
			$params = \array_merge($params, $albumIds);
89
		}
90
91
		$result = $this->execute($sql, $params);
92
		return $result->fetchAll(\PDO::FETCH_COLUMN|\PDO::FETCH_GROUP);
93
	}
94
95
	/**
96
	 * returns number of disks per album ID
97
	 *
98
	 * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given
99
	 * @param string $userId the user ID
100
	 * @return array int => int, keys are albums IDs and values are disk counts
101
	 */
102
	public function getDiscCountByAlbumId($albumIds, $userId) {
103
		$sql = 'SELECT `album_id`, MAX(`disk`) AS `disc_count`
104
				FROM `*PREFIX*music_tracks`
105
				WHERE `user_id` = ?
106
				GROUP BY `album_id` ';
107
		$params = [$userId];
108
109
		if ($albumIds !== null) {
110
			$sql .= 'HAVING `album_id` IN ' . $this->questionMarks(\count($albumIds));
111
			$params = \array_merge($params, $albumIds);
112
		}
113
114
		$result = $this->execute($sql, $params);
115
		$diskCountByAlbum = [];
116
		while ($row = $result->fetch()) {
117
			$diskCountByAlbum[$row['album_id']] = $row['disc_count'];
118
		}
119
		return $diskCountByAlbum;
120
	}
121
122
	/**
123
	 * Find all user's entities
124
	 *
125
	 * Overridden from \OCA\Music\Db\BaseMapper to add support for sorting by artist.
126
	 *
127
	 * @param string $userId
128
	 * @param integer $sortBy sort order of the result set
129
	 * @param integer|null $limit
130
	 * @param integer|null $offset
131
	 * @return Entity[]
132
	 */
133
	public function findAll($userId, $sortBy=SortBy::None, $limit=null, $offset=null) {
134
		if ($sortBy === SortBy::Parent) {
135
			$sql = 'SELECT `album`.* FROM `*PREFIX*music_albums` `album`
136
					INNER JOIN `*PREFIX*music_artists` `artist`
137
					ON `album`.`album_artist_id` = `artist`.`id`
138
					WHERE `album`.`user_id` = ?
139
					ORDER BY LOWER(`artist`.`name`)';
140
			$params = [$userId];
141
			return $this->findEntities($sql, $params, $limit, $offset);
142
		} else {
143
			return parent::findAll($userId, $sortBy, $limit, $offset);
144
		}
145
	}
146
147
	/**
148
	 * returns albums of a specified artist
149
	 * The artist may be an album_artist or the artist of a track
150
	 *
151
	 * @param integer $artistId ID of the artist
152
	 * @param string $userId the user ID
153
	 * @return Album[]
154
	 */
155
	public function findAllByArtist($artistId, $userId) {
156
		$sql = 'SELECT * FROM `*PREFIX*music_albums` `album` '.
157
			'WHERE `album`.`id` IN (SELECT DISTINCT `album`.`id` FROM '.
158
			'`*PREFIX*music_albums` `album` WHERE `album`.`album_artist_id` = ? AND '.
159
			'`album`.`user_id` = ? UNION SELECT `track`.`album_id` '.
160
			'FROM `*PREFIX*music_tracks` `track` WHERE `track`.`artist_id` = ? AND '.
161
			'`track`.`user_id` = ?) ORDER BY LOWER(`album`.`name`)';
162
		$params = [$artistId, $userId, $artistId, $userId];
163
		return $this->findEntities($sql, $params);
164
	}
165
166
	/**
167
	 * returns albums of a specified artist
168
	 * The artist must album_artist on the album, artists of individual tracks are not considered
169
	 *
170
	 * @param integer $artistId ID of the artist
171
	 * @param string $userId the user ID
172
	 * @return Album[]
173
	 */
174
	public function findAllByAlbumArtist($artistId, $userId) {
175
		$sql = $this->selectUserEntities('`album_artist_id` = ?');
176
		$params = [$userId, $artistId];
177
		return $this->findEntities($sql, $params);
178
	}
179
180
	/**
181
	 * @param int $genreId
182
	 * @param string $userId
183
	 * @param int|null $limit
184
	 * @param int|null $offset
185
	 * @return Artist[]
186
	 */
187
	public function findAllByGenre($genreId, $userId, $limit=null, $offset=null) {
188
		$sql = $this->selectUserEntities('EXISTS '.
189
				'(SELECT 1 FROM `*PREFIX*music_tracks` `track`
190
				  WHERE `*PREFIX*music_albums`.`id` = `track`.`album_id`
191
				  AND `track`.`genre_id` = ?)');
192
193
		$params = [$userId, $genreId];
194
		return $this->findEntities($sql, $params, $limit, $offset);
195
	}
196
197
	/**
198
	 * returns album that matches a name and an album artist ID
199
	 *
200
	 * @param string|null $albumName name of the album
201
	 * @param integer|null $albumArtistId ID of the album artist
202
	 * @param string $userId the user ID
203
	 * @return Album[]
204
	 */
205
	public function findAlbum($albumName, $albumArtistId, $userId) {
206
		$sql = $this->selectUserEntities();
207
		$params = [$userId];
208
209
		// add artist id check
210
		if ($albumArtistId === null) {
211
			$sql .= ' AND `album_artist_id` IS NULL ';
212
		} else {
213
			$sql .= ' AND `album_artist_id` = ? ';
214
			\array_push($params, $albumArtistId);
215
		}
216
217
		// add album name check
218
		if ($albumName === null) {
219
			$sql .= ' AND `name` IS NULL ';
220
		} else {
221
			$sql .= ' AND `name` = ? ';
222
			\array_push($params, $albumName);
223
		}
224
225
		return $this->findEntity($sql, $params);
226
	}
227
228
	/**
229
	 * @param integer $coverFileId
230
	 * @param integer $folderId
231
	 * @return boolean True if one or more albums were influenced
232
	 */
233
	public function updateFolderCover($coverFileId, $folderId) {
234
		$sql = 'SELECT DISTINCT `tracks`.`album_id`
235
				FROM `*PREFIX*music_tracks` `tracks`
236
				JOIN `*PREFIX*filecache` `files` ON `tracks`.`file_id` = `files`.`fileid`
237
				WHERE `files`.`parent` = ?';
238
		$params = [$folderId];
239
		$result = $this->execute($sql, $params);
240
241
		$updated = false;
242
		if ($result->rowCount()) {
243
			$sql = 'UPDATE `*PREFIX*music_albums`
244
					SET `cover_file_id` = ?
245
					WHERE `cover_file_id` IS NULL AND `id` IN (?)';
246
			$params = [$coverFileId, \join(",", $result->fetchAll(\PDO::FETCH_COLUMN))];
247
			$result = $this->execute($sql, $params);
248
			$updated = $result->rowCount() > 0;
249
		}
250
251
		return $updated;
252
	}
253
254
	/**
255
	 * @param integer $coverFileId
256
	 * @param integer $albumId
257
	 */
258
	public function setCover($coverFileId, $albumId) {
259
		$sql = 'UPDATE `*PREFIX*music_albums`
260
				SET `cover_file_id` = ?
261
				WHERE `id` = ?';
262
		$params = [$coverFileId, $albumId];
263
		$this->execute($sql, $params);
264
	}
265
266
	/**
267
	 * @param integer[] $coverFileIds
268
	 * @param string[]|null $userIds the users whose music library is targeted; all users are targeted if omitted
269
	 * @return Album[] albums which got modified (with incomplete data, only id and user are valid),
270
	 *         empty array if none
271
	 */
272
	public function removeCovers($coverFileIds, $userIds=null) {
273
		// find albums using the given file as cover
274
		$sql = 'SELECT `id`, `user_id` FROM `*PREFIX*music_albums` WHERE `cover_file_id` IN ' .
275
			$this->questionMarks(\count($coverFileIds));
276
		$params = $coverFileIds;
277
		if ($userIds !== null) {
278
			$sql .= ' AND `user_id` IN ' . $this->questionMarks(\count($userIds));
279
			$params = \array_merge($params, $userIds);
280
		}
281
		$albums = $this->findEntities($sql, $params);
282
283
		// if any albums found, remove the cover from those
284
		$count = \count($albums);
285
		if ($count) {
286
			$sql = 'UPDATE `*PREFIX*music_albums`
287
				SET `cover_file_id` = NULL
288
				WHERE `id` IN ' . $this->questionMarks($count);
289
			$params = Util::extractIds($albums);
290
			$this->execute($sql, $params);
291
		}
292
293
		return $albums;
294
	}
295
296
	/**
297
	 * @param string|null $userId target user; omit to target all users
298
	 * @return array of dictionaries with keys [albumId, userId, parentFolderId]
299
	 */
300
	public function getAlbumsWithoutCover($userId = null) {
301
		$sql = 'SELECT DISTINCT `albums`.`id`, `albums`.`user_id`, `files`.`parent`
302
				FROM `*PREFIX*music_albums` `albums`
303
				JOIN `*PREFIX*music_tracks` `tracks` ON `albums`.`id` = `tracks`.`album_id`
304
				JOIN `*PREFIX*filecache` `files` ON `tracks`.`file_id` = `files`.`fileid`
305
				WHERE `albums`.`cover_file_id` IS NULL';
306
		$params = [];
307
		if ($userId !== null) {
308
			$sql .= ' AND `albums`.`user_id` = ?';
309
			$params[] = $userId;
310
		}
311
		$result = $this->execute($sql, $params);
312
		$return = [];
313
		while ($row = $result->fetch()) {
314
			$return[] = [
315
				'albumId' => $row['id'],
316
				'userId' => $row['user_id'],
317
				'parentFolderId' => $row['parent']
318
			];
319
		}
320
		return $return;
321
	}
322
323
	/**
324
	 * @param integer $albumId
325
	 * @param integer $parentFolderId
326
	 * @return boolean True if a cover image was found and added for the album
327
	 */
328
	public function findAlbumCover($albumId, $parentFolderId) {
329
		$return = false;
330
		$coverNames = ['cover', 'albumart', 'front', 'folder'];
331
		$imagesSql = 'SELECT `fileid`, `name`
332
					FROM `*PREFIX*filecache`
333
					JOIN `*PREFIX*mimetypes` ON `*PREFIX*mimetypes`.`id` = `*PREFIX*filecache`.`mimetype`
334
					WHERE `parent` = ? AND `*PREFIX*mimetypes`.`mimetype` LIKE \'image%\'';
335
		$params = [$parentFolderId];
336
		$result = $this->execute($imagesSql, $params);
337
		$images = $result->fetchAll();
338
		if (\count($images)) {
339
			\usort($images, function ($imageA, $imageB) use ($coverNames) {
340
				$nameA = \strtolower($imageA['name']);
341
				$nameB = \strtolower($imageB['name']);
342
				$indexA = PHP_INT_MAX;
343
				$indexB = PHP_INT_MAX;
344
				foreach ($coverNames as $i => $coverName) {
345
					if ($indexA === PHP_INT_MAX && \strpos($nameA, $coverName) === 0) {
346
						$indexA = $i;
347
					}
348
					if ($indexB === PHP_INT_MAX && \strpos($nameB, $coverName) === 0) {
349
						$indexB = $i;
350
					}
351
					if ($indexA !== PHP_INT_MAX  && $indexB !== PHP_INT_MAX) {
352
						break;
353
					}
354
				}
355
				return $indexA > $indexB;
356
			});
357
			$imageId = $images[0]['fileid'];
358
			$this->setCover($imageId, $albumId);
359
			$return = true;
360
		}
361
		return $return;
362
	}
363
364
	/**
365
	 * Returns the count of albums an Artist is featured in
366
	 * @param integer $artistId
367
	 * @return integer
368
	 */
369
	public function countByArtist($artistId) {
370
		$sql = 'SELECT COUNT(*) AS count FROM '.
371
			'(SELECT DISTINCT `track`.`album_id` FROM '.
372
			'`*PREFIX*music_tracks` `track` WHERE `track`.`artist_id` = ? '.
373
			'UNION SELECT `album`.`id` FROM '.
374
			'`*PREFIX*music_albums` `album` WHERE `album`.`album_artist_id` = ?) tmp';
375
		$params = [$artistId, $artistId];
376
		$result = $this->execute($sql, $params);
377
		$row = $result->fetch();
378
		return $row['count'];
379
	}
380
381
	/**
382
	 * @see \OCA\Music\Db\BaseMapper::findUniqueEntity()
383
	 * @param Album $album
384
	 * @return Album
385
	 */
386
	protected function findUniqueEntity($album) {
387
		$sql = $this->selectUserEntities('`hash` = ?');
388
		return $this->findEntity($sql, [$album->getUserId(), $album->getHash()]);
389
	}
390
}
391