Passed
Push — master ( 35b7b2...cb91d5 )
by Pauli
02:01
created

AlbumMapper::getDiscCountByAlbumId()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

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