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

AlbumBusinessLayer::injectExtraFields()   A

Complexity

Conditions 6
Paths 5

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 13
nc 5
nop 3
dl 0
loc 24
ccs 14
cts 14
cp 1
crap 6
rs 9.2222
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\BusinessLayer;
16
17
use \OCA\Music\AppFramework\BusinessLayer\BusinessLayer;
18
use \OCA\Music\AppFramework\BusinessLayer\BusinessLayerException;
19
use \OCA\Music\AppFramework\Core\Logger;
20
21
use \OCA\Music\Db\AlbumMapper;
22
use \OCA\Music\Db\Album;
23
use \OCA\Music\Db\SortBy;
24
25
use \OCA\Music\Utility\Util;
26
27
class AlbumBusinessLayer extends BusinessLayer {
28
	private $logger;
29
30 8
	public function __construct(AlbumMapper $albumMapper, Logger $logger) {
31 8
		parent::__construct($albumMapper);
32 8
		$this->logger = $logger;
33 8
	}
34
35
	/**
36
	 * Return an album
37
	 * @param integer $albumId the id of the album
38
	 * @param string $userId the name of the user
39
	 * @return Album album
40
	 */
41 1
	public function find($albumId, $userId) {
42 1
		$album = parent::find($albumId, $userId);
43 1
		return $this->injectExtraFields([$album], $userId)[0];
44
	}
45
46
	/**
47
	 * Returns all albums
48
	 * @param string $userId the name of the user
49
	 * @param integer $sortBy Sorting order of the result, default to unspecified
50
	 * @param integer|null $limit
51
	 * @param integer|null $offset
52
	 * @return Album[] albums
53
	 */
54 2
	public function findAll($userId, $sortBy=SortBy::None, $limit=null, $offset=null) {
55 2
		$albums = parent::findAll($userId, $sortBy, $limit, $offset);
56 2
		return $this->injectExtraFields($albums, $userId, true);
57
	}
58
59
	/**
60
	 * Returns all albums filtered by artist (both album and track artists are considered)
61
	 * @param string $artistId the id of the artist
62
	 * @return Album[] albums
63
	 */
64 1
	public function findAllByArtist($artistId, $userId) {
65 1
		$albums = $this->mapper->findAllByArtist($artistId, $userId);
66 1
		return $this->injectExtraFields($albums, $userId);
67
	}
68
69
	/**
70
	 * Returns all albums filtered by album artist
71
	 * @param string $artistId the id of the artist
72
	 * @return Album[] albums
73
	 */
74
	public function findAllByAlbumArtist($artistId, $userId) {
75
		$albums = $this->mapper->findAllByAlbumArtist($artistId, $userId);
76
		$albums = $this->injectExtraFields($albums, $userId);
77
		\usort($albums, ['\OCA\Music\Db\Album', 'compareYearAndName']);
78
		return $albums;
79
	}
80
81
	/**
82
	 * Return all albums with name matching the search criteria
83
	 * @param string $name
84
	 * @param string $userId
85
	 * @param bool $fuzzy
86
	 * @param integer $limit
87
	 * @param integer $offset
88
	 * @return Album[]
89
	 */
90
	public function findAllByName($name, $userId, $fuzzy = false, $limit=null, $offset=null) {
91
		$albums = parent::findAllByName($name, $userId, $fuzzy, $limit, $offset);
92
		return $this->injectExtraFields($albums, $userId);
93
	}
94
95
	/**
96
	 * Add performing artists, release years, and disk counts to the given album objects
97
	 * @param Album[] $albums
98
	 * @param string $userId
99
	 * @param bool $allAlbums Set to true if $albums contains all albums of the user.
100
	 *                        This has now effect on the outcome but helps in optimizing
101
	 *                        the database query.
102
	 * @return Album[]
103
	 */
104 4
	private function injectExtraFields($albums, $userId, $allAlbums = false) {
105 4
		if (\count($albums) > 0) {
106
			// In case we are injecting data to a lot of albums, do not limit the
107
			// SQL SELECTs to only those albums. Very large amount of SQL host parameters
108
			// could cause problems with SQLite (see #239) and probably it would be bad for
109
			// performance also on other DBMSs. For the proper operation of this function,
110
			// it doesn't matter if we fetch data for some extra albums.
111 3
			$albumIds = ($allAlbums || \count($albums) >= 999)
112 3
					? null : Util::extractIds($albums);
113
114 3
			$artists = $this->mapper->getPerformingArtistsByAlbumId($albumIds, $userId);
115 3
			$years = $this->mapper->getYearsByAlbumId($albumIds, $userId);
116 3
			$diskCounts = $this->mapper->getDiscCountByAlbumId($albumIds, $userId);
117
118 3
			foreach ($albums as &$album) {
119 3
				$albumId = $album->getId();
120 3
				$album->setArtistIds($artists[$albumId]);
121 3
				$album->setNumberOfDisks($diskCounts[$albumId]);
122 3
				if (\array_key_exists($albumId, $years)) {
123 3
					$album->setYears($years[$albumId]);
124
				}
125
			}
126
		}
127 4
		return $albums;
128
	}
129
130
	/**
131
	 * Returns the count of albums an Artist is featured in
132
	 * @param integer $artistId
133
	 * @return integer
134
	 */
135
	public function countByArtist($artistId) {
136
		return $this->mapper->countByArtist($artistId);
137
	}
138
139
	public function findAlbumOwner($albumId) {
140
		$entities = $this->findById([$albumId]);
141
		if (\count($entities) != 1) {
142
			throw new BusinessLayerException(
143
					'Expected to find one album but got ' . \count($entities));
144
		} else {
145
			return $entities[0]->getUserId();
146
		}
147
	}
148
149
	/**
150
	 * Adds an album if it does not exist already or updates an existing album
151
	 * @param string $name the name of the album
152
	 * @param integer $albumArtistId
153
	 * @param string $userId
154
	 * @return Album The added/updated album
155
	 */
156 1
	public function addOrUpdateAlbum($name, $albumArtistId, $userId) {
157 1
		$album = new Album();
158 1
		$album->setName(Util::truncate($name, 256)); // some DB setups can't truncate automatically to column max size
159 1
		$album->setUserId($userId);
160 1
		$album->setAlbumArtistId($albumArtistId);
161
162
		// Generate hash from the set of fields forming the album identity to prevent duplicates.
163
		// The uniqueness of album name is evaluated in case-insensitive manner.
164 1
		$lowerName = \mb_strtolower($album->getName());
165 1
		$hash = \hash('md5', "$lowerName|$albumArtistId");
166 1
		$album->setHash($hash);
167
168 1
		return $this->mapper->insertOrUpdate($album);
169
	}
170
171
	/**
172
	 * Check if given file is used as cover for the given album
173
	 * @param int $albumId
174
	 * @param int[] $fileIds
175
	 * @return boolean
176
	 */
177
	public function albumCoverIsOneOfFiles($albumId, $fileIds) {
178
		$albums = $this->findById([$albumId]);
179
		return (\count($albums) && \in_array($albums[0]->getCoverFileId(), $fileIds));
180
	}
181
182
	/**
183
	 * updates the cover for albums in the specified folder without cover
184
	 * @param integer $coverFileId the file id of the cover image
185
	 * @param integer $folderId the file id of the folder where the albums are looked from
186
	 * @return true if one or more albums were influenced
187
	 */
188 1
	public function updateFolderCover($coverFileId, $folderId) {
189 1
		return $this->mapper->updateFolderCover($coverFileId, $folderId);
190
	}
191
192
	/**
193
	 * set cover file for a specified album
194
	 * @param integer $coverFileId the file id of the cover image
195
	 * @param integer $albumId the id of the album to be modified
196
	 */
197
	public function setCover($coverFileId, $albumId) {
198
		$this->mapper->setCover($coverFileId, $albumId);
199
	}
200
201
	/**
202
	 * removes the cover art from albums, replacement covers will be searched in a background task
203
	 * @param integer[] $coverFileIds the file IDs of the cover images
204
	 * @param string[]|null $userIds the users whose music library is targeted; all users are targeted if omitted
205
	 * @return Album[] albums which got modified, empty array if none
206
	 */
207 1
	public function removeCovers($coverFileIds, $userIds=null) {
208 1
		return $this->mapper->removeCovers($coverFileIds, $userIds);
209
	}
210
211
	/**
212
	 * try to find cover arts for albums without covers
213
	 * @param string|null $userId target user; omit to target all users
214
	 * @return array of users whose collections got modified
215
	 */
216
	public function findCovers($userId = null) {
217
		$affectedUsers = [];
218
		$albums = $this->mapper->getAlbumsWithoutCover($userId);
219
		foreach ($albums as $album) {
220
			if ($this->mapper->findAlbumCover($album['albumId'], $album['parentFolderId'])) {
221
				$affectedUsers[$album['userId']] = 1;
222
			}
223
		}
224
		return \array_keys($affectedUsers);
225
	}
226
}
227