Passed
Push — feature/329_Subsonic_API ( d9d298 )
by Pauli
10:35
created

AlbumBusinessLayer::injectArtistsAndYears()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 11
nc 5
nop 3
dl 0
loc 21
rs 9.2222
c 1
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
 * @copyright Morris Jobke 2013, 2014
11
 */
12
13
namespace OCA\Music\BusinessLayer;
14
15
use \OCA\Music\AppFramework\BusinessLayer\BusinessLayer;
16
use \OCA\Music\AppFramework\BusinessLayer\BusinessLayerException;
17
use \OCA\Music\AppFramework\Core\Logger;
18
19
use \OCA\Music\Db\AlbumMapper;
20
use \OCA\Music\Db\Album;
21
use \OCA\Music\Db\SortBy;
22
23
use \OCA\Music\Utility\Util;
24
25
class AlbumBusinessLayer extends BusinessLayer {
26
	private $logger;
27
28
	public function __construct(AlbumMapper $albumMapper, Logger $logger) {
29
		parent::__construct($albumMapper);
30
		$this->logger = $logger;
31
	}
32
33
	/**
34
	 * Return an album
35
	 * @param string $albumId the id of the album
36
	 * @param string $userId the name of the user
37
	 * @return Album album
38
	 */
39
	public function find($albumId, $userId) {
40
		$album = $this->mapper->find($albumId, $userId);
0 ignored issues
show
Bug introduced by
$albumId of type string is incompatible with the type integer expected by parameter $id of OCA\Music\Db\BaseMapper::find(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

40
		$album = $this->mapper->find(/** @scrutinizer ignore-type */ $albumId, $userId);
Loading history...
41
		return $this->injectArtistsAndYears([$album], $userId)[0];
42
	}
43
44
	/**
45
	 * Returns all albums
46
	 * @param string $userId the name of the user
47
	 * @param integer $sortBy Sorting order of the result, default to unspecified
48
	 * @param integer|null $limit
49
	 * @param integer|null $offset
50
	 * @return Album[] albums
51
	 */
52
	public function findAll($userId, $sortBy=SortBy::None, $limit=null, $offset=null) {
53
		$albums = $this->mapper->findAll($userId, $sortBy, $limit, $offset);
54
		return $this->injectArtistsAndYears($albums, $userId, true);
55
	}
56
57
	/**
58
	 * Returns all albums filtered by artist (both album and track artists are considered)
59
	 * @param string $artistId the id of the artist
60
	 * @return Album[] albums
61
	 */
62
	public function findAllByArtist($artistId, $userId) {
63
		$albums = $this->mapper->findAllByArtist($artistId, $userId);
64
		return $this->injectArtistsAndYears($albums, $userId);
65
	}
66
67
	/**
68
	 * Returns all albums filtered by album artist
69
	 * @param string $artistId the id of the artist
70
	 * @return Album[] albums
71
	 */
72
	public function findAllByAlbumArtist($artistId, $userId) {
73
		$albums = $this->mapper->findAllByAlbumArtist($artistId, $userId);
74
		return $this->injectArtistsAndYears($albums, $userId);
75
	}
76
77
	/**
78
	 * Return all albums with name matching the search criteria
79
	 * @param string $name
80
	 * @param string $userId
81
	 * @param bool $fuzzy
82
	 * @param integer $limit
83
	 * @param integer $offset
84
	 * @return Album[]
85
	 */
86
	public function findAllByName($name, $userId, $fuzzy = false, $limit=null, $offset=null) {
87
		$albums = parent::findAllByName($name, $userId, $fuzzy, $limit, $offset);
88
		return $this->injectArtistsAndYears($albums, $userId);
89
	}
90
91
	/**
92
	 * Add album artists and release years to the given album objects
93
	 * @param Album[] $albums
94
	 * @param string $userId
95
	 * @param bool $allAlbums Set to true if $albums contains all albums of the user.
96
	 *                        This has now effect on the outcome but helps in optimizing
97
	 *                        the database query.
98
	 * @return Album[]
99
	 */
100
	private function injectArtistsAndYears($albums, $userId, $allAlbums = false) {
101
		if (\count($albums) > 0) {
102
			// In case we are injecting data to a lot of albums, do not limit the
103
			// SQL SELECTs to only those albums. Very large amount of SQL host parameters
104
			// could cause problems with SQLite (see #239) and probably it would be bad for
105
			// performance also on other DBMSs. For the proper operation of this function,
106
			// it doesn't matter if we fetch data for some extra albums.
107
			$albumIds = ($allAlbums || \count($albums) >= 999)
108
					? null : Util::extractIds($albums);
109
110
			$albumArtists = $this->mapper->getAlbumArtistsByAlbumId($albumIds, $userId);
111
			$years = $this->mapper->getYearsByAlbumId($albumIds, $userId);
112
			foreach ($albums as &$album) {
113
				$albumId = $album->getId();
114
				$album->setArtistIds($albumArtists[$albumId]);
115
				if (\array_key_exists($albumId, $years)) {
116
					$album->setYears($years[$albumId]);
117
				}
118
			}
119
		}
120
		return $albums;
121
	}
122
123
	/**
124
	 * Returns the count of albums an Artist is featured in
125
	 * @param integer $artistId
126
	 * @return integer
127
	 */
128
	public function countByArtist($artistId) {
129
		return $this->mapper->countByArtist($artistId);
130
	}
131
132
	public function findAlbumOwner($albumId) {
133
		$entities = $this->mapper->findById([$albumId]);
134
		if (\count($entities) != 1) {
135
			throw new \OCA\Music\AppFramework\BusinessLayer\BusinessLayerException(
136
					'Expected to find one album but got ' . \count($entities));
137
		} else {
138
			return $entities[0]->getUserId();
139
		}
140
	}
141
142
	/**
143
	 * Adds an album if it does not exist already or updates an existing album
144
	 * @param string $name the name of the album
145
	 * @param string $discnumber the disk number of this album's disk
146
	 * @param integer $albumArtistId
147
	 * @param string $userId
148
	 * @return Album The added/updated album
149
	 */
150
	public function addOrUpdateAlbum($name, $discnumber, $albumArtistId, $userId) {
151
		$album = new Album();
152
		$album->setName($name);
153
		$album->setDisk($discnumber);
0 ignored issues
show
Bug introduced by
$discnumber of type string is incompatible with the type integer expected by parameter $discnumber of OCA\Music\Db\Album::setDisk(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

153
		$album->setDisk(/** @scrutinizer ignore-type */ $discnumber);
Loading history...
154
		$album->setUserId($userId);
155
		$album->setAlbumArtistId($albumArtistId);
156
157
		// Generate hash from the set of fields forming the album identity to prevent duplicates.
158
		// The uniqueness of album name is evaluated in case-insensitive manner.
159
		$lowerName = \mb_strtolower($name);
160
		$hash = \hash('md5', "$lowerName|$discnumber|$albumArtistId");
161
		$album->setHash($hash);
162
163
		return $this->mapper->insertOrUpdate($album);
164
	}
165
166
	/**
167
	 * Check if given file is used as cover for the given album
168
	 * @param int $albumId
169
	 * @param int[] $fileIds
170
	 * @return boolean
171
	 */
172
	public function albumCoverIsOneOfFiles($albumId, $fileIds) {
173
		$albums = $this->mapper->findById([$albumId]);
174
		return (\count($albums) && \in_array($albums[0]->getCoverFileId(), $fileIds));
175
	}
176
177
	/**
178
	 * updates the cover for albums in the specified folder without cover
179
	 * @param integer $coverFileId the file id of the cover image
180
	 * @param integer $folderId the file id of the folder where the albums are looked from
181
	 * @return true if one or more albums were influenced
182
	 */
183
	public function updateFolderCover($coverFileId, $folderId) {
184
		return $this->mapper->updateFolderCover($coverFileId, $folderId);
185
	}
186
187
	/**
188
	 * set cover file for a specified album
189
	 * @param integer $coverFileId the file id of the cover image
190
	 * @param integer $albumId the id of the album to be modified
191
	 */
192
	public function setCover($coverFileId, $albumId) {
193
		$this->mapper->setCover($coverFileId, $albumId);
194
	}
195
196
	/**
197
	 * removes the cover art from albums, replacement covers will be searched in a background task
198
	 * @param integer[] $coverFileIds the file IDs of the cover images
199
	 * @param string[]|null $userIds the users whose music library is targeted; all users are targeted if omitted
200
	 * @return Album[] albums which got modified, empty array if none
201
	 */
202
	public function removeCovers($coverFileIds, $userIds=null) {
203
		return $this->mapper->removeCovers($coverFileIds, $userIds);
204
	}
205
206
	/**
207
	 * try to find cover arts for albums without covers
208
	 * @param string|null $userId target user; omit to target all users
209
	 * @return array of users whose collections got modified
210
	 */
211
	public function findCovers($userId = null) {
212
		$affectedUsers = [];
213
		$albums = $this->mapper->getAlbumsWithoutCover($userId);
214
		foreach ($albums as $album) {
215
			if ($this->mapper->findAlbumCover($album['albumId'], $album['parentFolderId'])) {
216
				$affectedUsers[$album['userId']] = 1;
217
			}
218
		}
219
		return \array_keys($affectedUsers);
220
	}
221
}
222