Passed
Push — master ( cb91d5...3e9848 )
by Pauli
02:06
created

TrackBusinessLayer::addOrUpdateTrack()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 13
nc 1
nop 11
dl 0
loc 16
ccs 14
cts 14
cp 1
crap 1
rs 9.8333
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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
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\Core\Logger;
19
20
use \OCA\Music\Db\TrackMapper;
21
use \OCA\Music\Db\Track;
22
23
use \OCA\Music\Utility\Util;
24
25
use \OCP\AppFramework\Db\DoesNotExistException;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Db\DoesNotExistException 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...
26
use \OCP\AppFramework\Db\MultipleObjectsReturnedException;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Db\Mult...bjectsReturnedException 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...
27
28
class TrackBusinessLayer extends BusinessLayer {
29
	private $logger;
30
31 7
	public function __construct(TrackMapper $trackMapper, Logger $logger) {
32 7
		parent::__construct($trackMapper);
33 7
		$this->logger = $logger;
34 7
	}
35
36
	/**
37
	 * Returns all tracks filtered by artist
38
	 * @param string $artistId the id of the artist
39
	 * @param string $userId the name of the user
40
	 * @return array of tracks
41
	 */
42 1
	public function findAllByArtist($artistId, $userId) {
43 1
		return $this->mapper->findAllByArtist($artistId, $userId);
44
	}
45
46
	/**
47
	 * Returns all tracks filtered by album
48
	 * @param string $albumId the id of the album
49
	 * @param string $userId the name of the user
50
	 * @return \OCA\Music\Db\Track[] tracks
51
	 */
52 1
	public function findAllByAlbum($albumId, $userId, $artistId = null) {
53 1
		return $this->mapper->findAllByAlbum($albumId, $userId, $artistId);
54
	}
55
56
	/**
57
	 * Returns all tracks filtered by parent folder
58
	 * @param integer $folderId the id of the track
59
	 * @param string $userId the name of the user
60
	 * @return \OCA\Music\Db\Track[] tracks
61
	 */
62
	public function findAllByFolder($folderId, $userId) {
63
		return $this->mapper->findAllByFolder($folderId, $userId);
64
	}
65
66
	/**
67
	 * Returns all tracks filtered by name (of track/album/artist)
68
	 * @param string $name the name of the track/album/artist
69
	 * @param string $userId the name of the user
70
	 * @return \OCA\Music\Db\Track[] tracks
71
	 */
72
	public function findAllByNameRecursive($name, $userId) {
73
		return $this->mapper->findAllByNameRecursive($name, $userId);
74
	}
75
76
	/**
77
	 * Returns track specified by name and/or artist name
78
	 * @param string|null $name the name of the track
79
	 * @param string|null $artistName the name of the artist
80
	 * @param string $userId the name of the user
81
	 * @return \OCA\Music\Db\Track|null Mathing track if the criteria uniquely defines one
82
	 */
83
	public function findByNameAndArtistName($name, $artistName, $userId) {
84
		try {
85
			return $this->mapper->findByNameAndArtistName($name, $artistName, $userId);
86
		} catch (DoesNotExistException $e) {
87
			$this->logger->log("No track found with title '$name' and artist '$artistName'", 'debug');
88
			return null;
89
		} catch (MultipleObjectsReturnedException $e) {
90
			$this->logger->log("More than on track found with title '$name' and artist '$artistName'", 'debug');
91
			return null;
92
		}
93
	}
94
95
	/**
96
	 * Returns the track for a file id
97
	 * @param string $fileId the file id of the track
98
	 * @param string $userId the name of the user
99
	 * @return \OCA\Music\Db\Track|null track
100
	 */
101 1
	public function findByFileId($fileId, $userId) {
102
		try {
103 1
			return $this->mapper->findByFileId($fileId, $userId);
104
		} catch (DoesNotExistException $e) {
105
			return null;
106
		}
107
	}
108
109
	/**
110
	 * Returns file IDs of all indexed tracks of the user
111
	 * @param string $userId
112
	 * @return int[]
113
	 */
114
	public function findAllFileIds($userId) {
115
		return $this->mapper->findAllFileIds($userId);
116
	}
117
118
	/**
119
	 * Returns all folders of the user containing indexed tracks, along with the contained track IDs
120
	 * @param string $userId
121
	 * @param Folder $userHome
0 ignored issues
show
Bug introduced by
The type OCA\Music\BusinessLayer\Folder 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...
122
	 * @return array of entries like {id: int, name: string, path: string, trackIds: int[]}
123
	 */
124
	public function findAllFolders($userId, $userHome) {
125
		// All tracks of the user, grouped by their parent folders. Some of the parent folders
126
		// may be owned by other users and are invisible to this user (in case of shared files).
127
		$tracksByFolder = $this->mapper->findTrackAndFolderIds($userId);
128
129
		// Get the folder names and paths for ordinary local folders directly from the DB.
130
		// This is significantly more efficient than using the Files API because we need to
131
		// run only single DB query instead of one per folder.
132
		$folderNamesAndPaths = $this->mapper->findNodeNamesAndPaths(
133
				\array_keys($tracksByFolder), $userHome->getStorage()->getId());
134
135
		// root folder has to be handled as a special case because shared files from
136
		// many folders may be shown to this user mapped under the root folder
137
		$rootFolderTracks = [];
138
139
		// Build the final results. Use the previously fetched data for the ordinary
140
		// local folders and query the data through the Files API for the more special cases.
141
		$result = [];
142
		foreach ($tracksByFolder as $folderId => $trackIds) {
143
			if (isset($folderNamesAndPaths[$folderId])) {
144
				// normal folder within the user home storage
145
				$entry = $folderNamesAndPaths[$folderId];
146
				// remove the "files" from the beginning of the folder path
147
				$entry['path'] = \substr($entry['path'], 5);
148
				// special handling for the root folder
149
				if ($entry['path'] === '') {
150
					$entry = null;
151
				}
152
			}
153
			else {
154
				// shared folder or parent folder of a shared file or an externally mounted folder
155
				$folderNode = $userHome->getById($folderId);
156
				if (\count($folderNode) === 0) {
157
					// other user's folder with files shared with this user (mapped under root)
158
					$entry = null;
159
				}
160
				else {
161
					$entry = [
162
						'name' => $folderNode[0]->getName(),
163
						'path' => $userHome->getRelativePath($folderNode[0]->getPath())
164
					];
165
				}
166
			}
167
168
			if ($entry) {
169
				$entry['trackIds'] = $trackIds;
170
				$entry['id'] = $folderId;
171
				$result[] = $entry;
172
			} else {
173
				$rootFolderTracks = \array_merge($rootFolderTracks, $trackIds);
174
			}
175
		}
176
177
		// add the root folder if it contains any tracks
178
		if (!empty($rootFolderTracks)) {
179
			$result[] = [
180
				'name' => '',
181
				'path' => '/',
182
				'trackIds' => $rootFolderTracks,
183
				'id' => $userHome->getId()
184
			];
185
		}
186
187
		return $result;
188
	}
189
190
	/**
191
	 * @param integer $artistId
192
	 * @return integer
193
	 */
194
	public function countByArtist($artistId) {
195
		return $this->mapper->countByArtist($artistId);
196
	}
197
198
	/**
199
	 * @param integer $albumId
200
	 * @return integer
201
	 */
202
	public function countByAlbum($albumId) {
203
		return $this->mapper->countByAlbum($albumId);
204
	}
205
206
	/**
207
	 * Adds a track if it does not exist already or updates an existing track
208
	 * @param string $title the title of the track
209
	 * @param int|null $number the number of the track
210
	 * @param int|null $discNumber the number of the disc
211
	 * @param int|null $year the year of the release
212
	 * @param int $artistId the artist id of the track
213
	 * @param int $albumId the album id of the track
214
	 * @param int $fileId the file id of the track
215
	 * @param string $mimetype the mimetype of the track
216
	 * @param string $userId the name of the user
217
	 * @param int $length track length in seconds
218
	 * @param int $bitrate track bitrate in bits (not kbits)
219
	 * @return \OCA\Music\Db\Track The added/updated track
220
	 */
221 1
	public function addOrUpdateTrack(
222
			$title, $number, $discNumber, $year, $artistId, $albumId, $fileId,
223
			$mimetype, $userId, $length=null, $bitrate=null) {
224 1
		$track = new Track();
225 1
		$track->setTitle(Util::truncate($title, 256)); // some DB setups can't truncate automatically to column max size
226 1
		$track->setNumber($number);
227 1
		$track->setDisk($discNumber);
228 1
		$track->setYear($year);
229 1
		$track->setArtistId($artistId);
230 1
		$track->setAlbumId($albumId);
231 1
		$track->setFileId($fileId);
232 1
		$track->setMimetype($mimetype);
233 1
		$track->setUserId($userId);
234 1
		$track->setLength($length);
235 1
		$track->setBitrate($bitrate);
236 1
		return $this->mapper->insertOrUpdate($track);
237
	}
238
239
	/**
240
	 * Deletes a track
241
	 * @param int[] $fileIds file IDs of the tracks to delete
242
	 * @param string[]|null $userIds the target users; if omitted, the tracks matching the
243
	 *                      $fileIds are deleted from all users
244
	 * @return array|false  False is returned if no such track was found; otherwise array of six arrays
245
	 *         (named 'deletedTracks', 'remainingAlbums', 'remainingArtists', 'obsoleteAlbums',
246
	 *         'obsoleteArtists', and 'affectedUsers'). These contain the track, album, artist, and
247
	 *         user IDs of the deleted tracks. The 'obsolete' entities are such which no longer
248
	 *         have any tracks while 'remaining' entities have some left.
249
	 */
250 3
	public function deleteTracks($fileIds, $userIds = null) {
251 3
		$tracks = ($userIds !== null)
252
			? $this->mapper->findByFileIds($fileIds, $userIds)
253 3
			: $this->mapper->findAllByFileIds($fileIds);
254
255 3
		if (\count($tracks) === 0) {
256 1
			$result = false;
257
		} else {
258
			// delete all the matching tracks
259 2
			$trackIds = Util::extractIds($tracks);
260 2
			$this->deleteById($trackIds);
261
262
			// find all distinct albums, artists, and users of the deleted tracks
263 2
			$artists = [];
264 2
			$albums = [];
265 2
			$users = [];
266 2
			foreach ($tracks as $track) {
267 2
				$artists[$track->getArtistId()] = 1;
268 2
				$albums[$track->getAlbumId()] = 1;
269 2
				$users[$track->getUserId()] = 1;
270
			}
271 2
			$artists = \array_keys($artists);
272 2
			$albums = \array_keys($albums);
273 2
			$users = \array_keys($users);
274
275
			// categorize each artist as 'remaining' or 'obsolete'
276 2
			$remainingArtists = [];
277 2
			$obsoleteArtists = [];
278 2
			foreach ($artists as $artistId) {
279 2
				$result = $this->mapper->countByArtist($artistId);
280 2
				if ($result === '0') {
281 1
					$obsoleteArtists[] = $artistId;
282
				} else {
283 2
					$remainingArtists[] = $artistId;
284
				}
285
			}
286
287
			// categorize each album as 'remaining' or 'obsolete'
288 2
			$remainingAlbums = [];
289 2
			$obsoleteAlbums = [];
290 2
			foreach ($albums as $albumId) {
291 2
				$result = $this->mapper->countByAlbum($albumId);
292 2
				if ($result === '0') {
293 1
					$obsoleteAlbums[] = $albumId;
294
				} else {
295 2
					$remainingAlbums[] = $albumId;
296
				}
297
			}
298
299
			$result = [
300 2
				'deletedTracks'    => $trackIds,
301 2
				'remainingAlbums'  => $remainingAlbums,
302 2
				'remainingArtists' => $remainingArtists,
303 2
				'obsoleteAlbums'   => $obsoleteAlbums,
304 2
				'obsoleteArtists'  => $obsoleteArtists,
305 2
				'affectedUsers'    => $users
306
			];
307
		}
308
309 3
		return $result;
310
	}
311
}
312