Passed
Push — feature/329_Subsonic_API ( a9dee6...9d1353 )
by Pauli
14:33
created

TrackBusinessLayer::addOrUpdateTrack()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 10
dl 0
loc 15
rs 9.8666
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 - 2019
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
27
class TrackBusinessLayer extends BusinessLayer {
28
	private $logger;
29
30
	public function __construct(TrackMapper $trackMapper, Logger $logger) {
31
		parent::__construct($trackMapper);
32
		$this->logger = $logger;
33
	}
34
35
	/**
36
	 * Returns all tracks filtered by artist
37
	 * @param string $artistId the id of the artist
38
	 * @param string $userId the name of the user
39
	 * @return array of tracks
40
	 */
41
	public function findAllByArtist($artistId, $userId) {
42
		return $this->mapper->findAllByArtist($artistId, $userId);
43
	}
44
45
	/**
46
	 * Returns all tracks filtered by album
47
	 * @param string $albumId the id of the album
48
	 * @param string $userId the name of the user
49
	 * @return \OCA\Music\Db\Track[] tracks
50
	 */
51
	public function findAllByAlbum($albumId, $userId, $artistId = null) {
52
		return $this->mapper->findAllByAlbum($albumId, $userId, $artistId);
53
	}
54
55
	/**
56
	 * Returns all tracks filtered by parent folder
57
	 * @param integer $folderId the id of the track
58
	 * @param string $userId the name of the user
59
	 * @return \OCA\Music\Db\Track[] tracks
60
	 */
61
	public function findAllByFolder($folderId, $userId) {
62
		return $this->mapper->findAllByFolder($folderId, $userId);
63
	}
64
65
	/**
66
	 * Returns all tracks filtered by name (of track/album/artist)
67
	 * @param string $name the name of the track/album/artist
68
	 * @param string $userId the name of the user
69
	 * @return \OCA\Music\Db\Track[] tracks
70
	 */
71
	public function findAllByNameRecursive($name, $userId) {
72
		return $this->mapper->findAllByNameRecursive($name, $userId);
73
	}
74
75
	/**
76
	 * Returns the track for a file id
77
	 * @param string $fileId the file id of the track
78
	 * @param string $userId the name of the user
79
	 * @return \OCA\Music\Db\Track|null track
80
	 */
81
	public function findByFileId($fileId, $userId) {
82
		try {
83
			return $this->mapper->findByFileId($fileId, $userId);
84
		} catch (DoesNotExistException $e) {
85
			return null;
86
		}
87
	}
88
89
	/**
90
	 * Returns file IDs of all indexed tracks of the user
91
	 * @param string $userId
92
	 * @return int[]
93
	 */
94
	public function findAllFileIds($userId) {
95
		return $this->mapper->findAllFileIds($userId);
96
	}
97
98
	/**
99
	 * Returns all folders of the user containing indexed tracks, along with the contained track IDs
100
	 * @param string $userId
101
	 * @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...
102
	 * @return array of entries like {id: int, name: string, path: string, trackIds: int[]}
103
	 */
104
	public function findAllFolders($userId, $userHome) {
105
		// All tracks of the user, grouped by their parent folders. Some of the parent folders
106
		// may be owned by other users and are invisible to this user (in case of shared files).
107
		$tracksByFolder = $this->mapper->findTrackAndFolderIds($userId);
108
109
		// Get the folder names and paths for ordinary local folders directly from the DB.
110
		// This is significantly more efficient than using the Files API because we need to
111
		// run only single DB query instead of one per folder.
112
		$folderNamesAndPaths = $this->mapper->findNodeNamesAndPaths(
113
				\array_keys($tracksByFolder), $userHome->getStorage()->getId());
114
115
		// root folder has to be handled as a special case because shared files from
116
		// many folders may be shown to this user mapped under the root folder
117
		$rootFolderTracks = [];
118
119
		// Build the final results. Use the previously fetched data for the ordinary
120
		// local folders and query the data through the Files API for the more special cases.
121
		$result = [];
122
		foreach ($tracksByFolder as $folderId => $trackIds) {
123
			if (isset($folderNamesAndPaths[$folderId])) {
124
				// normal folder within the user home storage
125
				$entry = $folderNamesAndPaths[$folderId];
126
				// remove the "files" from the beginning of the folder path
127
				$entry['path'] = \substr($entry['path'], 5);
128
				// special handling for the root folder
129
				if ($entry['path'] === '') {
130
					$entry = null;
131
				}
132
			}
133
			else {
134
				// shared folder or parent folder of a shared file or an externally mounted folder
135
				$folderNode = $userHome->getById($folderId);
136
				if (\count($folderNode) === 0) {
137
					// other user's folder with files shared with this user (mapped under root)
138
					$entry = null;
139
				}
140
				else {
141
					$entry = [
142
						'name' => $folderNode[0]->getName(),
143
						'path' => $userHome->getRelativePath($folderNode[0]->getPath())
144
					];
145
				}
146
			}
147
148
			if ($entry) {
149
				$entry['trackIds'] = $trackIds;
150
				$entry['id'] = $folderId;
151
				$result[] = $entry;
152
			} else {
153
				$rootFolderTracks = \array_merge($rootFolderTracks, $trackIds);
154
			}
155
		}
156
157
		// add the root folder if it contains any tracks
158
		if (!empty($rootFolderTracks)) {
159
			$result[] = [
160
				'name' => '',
161
				'path' => '/',
162
				'trackIds' => $rootFolderTracks,
163
				'id' => $userHome->getId()
164
			];
165
		}
166
167
		return $result;
168
	}
169
170
	/**
171
	 * @param integer $artistId
172
	 * @return integer
173
	 */
174
	public function countByArtist($artistId) {
175
		return $this->mapper->countByArtist($artistId);
176
	}
177
178
	/**
179
	 * @param integer $albumId
180
	 * @return integer
181
	 */
182
	public function countByAlbum($albumId) {
183
		return $this->mapper->countByAlbum($albumId);
184
	}
185
186
	/**
187
	 * Adds a track if it does not exist already or updates an existing track
188
	 * @param string $title the title of the track
189
	 * @param string $number the number of the track
190
	 * @param string $year the year of the release
191
	 * @param string $artistId the artist id of the track
192
	 * @param string $albumId the album id of the track
193
	 * @param string $fileId the file id of the track
194
	 * @param string $mimetype the mimetype of the track
195
	 * @param string $userId the name of the user
196
	 * @param int $length track length in seconds
197
	 * @param int $bitrate track bitrate in bits (not kbits)
198
	 * @return \OCA\Music\Db\Track The added/updated track
199
	 */
200
	public function addOrUpdateTrack(
201
			$title, $number, $year, $artistId, $albumId, $fileId,
202
			$mimetype, $userId, $length=null, $bitrate=null) {
203
		$track = new Track();
204
		$track->setTitle(Util::truncate($title, 256)); // some DB setups can't truncate automatically to column max size
205
		$track->setNumber($number);
0 ignored issues
show
Bug introduced by
$number of type string is incompatible with the type integer expected by parameter $number of OCA\Music\Db\Track::setNumber(). ( Ignorable by Annotation )

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

205
		$track->setNumber(/** @scrutinizer ignore-type */ $number);
Loading history...
206
		$track->setYear($year);
0 ignored issues
show
Bug introduced by
$year of type string is incompatible with the type integer expected by parameter $year of OCA\Music\Db\Track::setYear(). ( Ignorable by Annotation )

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

206
		$track->setYear(/** @scrutinizer ignore-type */ $year);
Loading history...
207
		$track->setArtistId($artistId);
0 ignored issues
show
Bug introduced by
$artistId of type string is incompatible with the type integer expected by parameter $artistId of OCA\Music\Db\Track::setArtistId(). ( Ignorable by Annotation )

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

207
		$track->setArtistId(/** @scrutinizer ignore-type */ $artistId);
Loading history...
208
		$track->setAlbumId($albumId);
0 ignored issues
show
Bug introduced by
$albumId of type string is incompatible with the type integer expected by parameter $albumId of OCA\Music\Db\Track::setAlbumId(). ( Ignorable by Annotation )

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

208
		$track->setAlbumId(/** @scrutinizer ignore-type */ $albumId);
Loading history...
209
		$track->setFileId($fileId);
0 ignored issues
show
Bug introduced by
$fileId of type string is incompatible with the type integer expected by parameter $fileId of OCA\Music\Db\Track::setFileId(). ( Ignorable by Annotation )

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

209
		$track->setFileId(/** @scrutinizer ignore-type */ $fileId);
Loading history...
210
		$track->setMimetype($mimetype);
211
		$track->setUserId($userId);
212
		$track->setLength($length);
213
		$track->setBitrate($bitrate);
214
		return $this->mapper->insertOrUpdate($track);
215
	}
216
217
	/**
218
	 * Deletes a track
219
	 * @param int[] $fileIds file IDs of the tracks to delete
220
	 * @param string[]|null $userIds the target users; if omitted, the tracks matching the
221
	 *                      $fileIds are deleted from all users
222
	 * @return False if no such track was found; otherwise array of six arrays
223
	 *         (named 'deletedTracks', 'remainingAlbums', 'remainingArtists', 'obsoleteAlbums',
224
	 *         'obsoleteArtists', and 'affectedUsers'). These contain the track, album, artist, and
225
	 *         user IDs of the deleted tracks. The 'obsolete' entities are such which no longer
226
	 *         have any tracks while 'remaining' entities have some left.
227
	 */
228
	public function deleteTracks($fileIds, $userIds = null) {
229
		$tracks = ($userIds !== null)
230
			? $this->mapper->findByFileIds($fileIds, $userIds)
231
			: $this->mapper->findAllByFileIds($fileIds);
232
233
		if (\count($tracks) === 0) {
234
			$result = false;
235
		} else {
236
			// delete all the matching tracks
237
			$trackIds = Util::extractIds($tracks);
238
			$this->deleteById($trackIds);
239
240
			// find all distinct albums, artists, and users of the deleted tracks
241
			$artists = [];
242
			$albums = [];
243
			$users = [];
244
			foreach ($tracks as $track) {
245
				$artists[$track->getArtistId()] = 1;
246
				$albums[$track->getAlbumId()] = 1;
247
				$users[$track->getUserId()] = 1;
248
			}
249
			$artists = \array_keys($artists);
250
			$albums = \array_keys($albums);
251
			$users = \array_keys($users);
252
253
			// categorize each artist as 'remaining' or 'obsolete'
254
			$remainingArtists = [];
255
			$obsoleteArtists = [];
256
			foreach ($artists as $artistId) {
257
				$result = $this->mapper->countByArtist($artistId);
258
				if ($result === '0') {
259
					$obsoleteArtists[] = $artistId;
260
				} else {
261
					$remainingArtists[] = $artistId;
262
				}
263
			}
264
265
			// categorize each album as 'remaining' or 'obsolete'
266
			$remainingAlbums = [];
267
			$obsoleteAlbums = [];
268
			foreach ($albums as $albumId) {
269
				$result = $this->mapper->countByAlbum($albumId);
270
				if ($result === '0') {
271
					$obsoleteAlbums[] = $albumId;
272
				} else {
273
					$remainingAlbums[] = $albumId;
274
				}
275
			}
276
277
			$result = [
278
				'deletedTracks'    => $trackIds,
279
				'remainingAlbums'  => $remainingAlbums,
280
				'remainingArtists' => $remainingArtists,
281
				'obsoleteAlbums'   => $obsoleteAlbums,
282
				'obsoleteArtists'  => $obsoleteArtists,
283
				'affectedUsers'    => $users
284
			];
285
		}
286
287
		return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type array<string,array|mixed> which is incompatible with the documented return type false.
Loading history...
288
	}
289
}
290