Completed
Push — master ( 1d670a...d65951 )
by Morris
02:28
created

ApiController   B

Complexity

Total Complexity 43

Size/Duplication

Total Lines 332
Duplicated Lines 18.37 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 65.13%

Importance

Changes 4
Bugs 1 Features 0
Metric Value
wmc 43
c 4
b 1
f 0
lcom 1
cbo 8
dl 61
loc 332
ccs 127
cts 195
cp 0.6513
rs 8.3158

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 20 1
A getIdFromSlug() 0 5 1
C collection() 0 38 7
C artists() 0 26 7
B artist() 22 22 4
B albums() 0 22 5
B album() 23 23 4
B tracks() 0 23 5
A track() 0 6 1
A trackByFileId() 0 5 1
A scan() 0 13 2
B download() 8 28 3
A cover() 8 21 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ApiController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ApiController, and based on these observations, apply Extract Interface, too.

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\Controller;
14
15
use OCA\Music\Db\Artist;
16
use OCA\Music\Db\Track;
17
use \OCP\AppFramework\Controller;
18
use \OCP\AppFramework\Http;
19
use \OCP\AppFramework\Http\JSONResponse;
20
use \OCP\AppFramework\Http\Response;
21
use \OCP\Files\Folder;
22
use \OCP\IL10N;
23
use \OCP\IRequest;
24
use \OCP\IURLGenerator;
25
26
use \OCP\AppFramework\Db\DoesNotExistException;
27
28
use \OCA\Music\BusinessLayer\TrackBusinessLayer;
29
use \OCA\Music\BusinessLayer\ArtistBusinessLayer;
30
use \OCA\Music\BusinessLayer\AlbumBusinessLayer;
31
use \OCA\Music\Http\FileResponse;
32
use \OCA\Music\Utility\Scanner;
33
34
35
class ApiController extends Controller {
36
37
	/** @var IL10N */
38
	private $l10n;
39
	/** @var TrackBusinessLayer */
40
	private $trackBusinessLayer;
41
	/** @var ArtistBusinessLayer */
42
	private $artistBusinessLayer;
43
	/** @var AlbumBusinessLayer */
44
	private $albumBusinessLayer;
45
	/** @var Scanner */
46
	private $scanner;
47
	/** @var string */
48
	private $userId;
49
	/** @var IURLGenerator */
50
	private $urlGenerator;
51
	/** @var Folder */
52
	private $userFolder;
53
54 48
	public function __construct($appname,
55
								IRequest $request,
56
								IURLGenerator $urlGenerator,
57
								TrackBusinessLayer $trackbusinesslayer,
58
								ArtistBusinessLayer $artistbusinesslayer,
59
								AlbumBusinessLayer $albumbusinesslayer,
60
								Scanner $scanner,
61
								$userId,
62
								$l10n,
63
								Folder $userFolder){
64 48
		parent::__construct($appname, $request);
65 48
		$this->l10n = $l10n;
66 48
		$this->trackBusinessLayer = $trackbusinesslayer;
67 48
		$this->artistBusinessLayer = $artistbusinesslayer;
68 48
		$this->albumBusinessLayer = $albumbusinesslayer;
69 48
		$this->scanner = $scanner;
70 48
		$this->userId = $userId;
71 48
		$this->urlGenerator = $urlGenerator;
72 48
		$this->userFolder = $userFolder;
73 48
	}
74
75
	/**
76
	 * Extracts the id from an unique slug (id-slug)
77
	 * @param string $slug the slug
78
	 * @return string the id
79
	 */
80 15
	protected function getIdFromSlug($slug){
81 15
		$split = explode('-', $slug, 2);
82
83 15
		return $split[0];
84
	}
85
86
	/**
87
	 * @NoAdminRequired
88
	 * @NoCSRFRequired
89
	 */
90
	public function collection() {
91
		/** @var Artist[] $allArtists */
92
		$allArtists = $this->artistBusinessLayer->findAll($this->userId);
93
		$allArtistsById = array();
94
		foreach ($allArtists as &$artist) {
95
			$allArtistsById[$artist->getId()] = $artist->toCollection($this->l10n);
96
		}
97
98
		$allAlbums = $this->albumBusinessLayer->findAll($this->userId);
99
		$allAlbumsById = array();
100
		foreach ($allAlbums as &$album) {
101
			$allAlbumsById[$album->getId()] = $album->toCollection($this->urlGenerator, $this->l10n);
102
		}
103
104
		/** @var Track[] $allTracks */
105
		$allTracks = $this->trackBusinessLayer->findAll($this->userId);
106
107
		$artists = array();
108
		foreach ($allTracks as $track) {
109
			$artist = &$allArtistsById[$track->getArtistId()];
110
			if (!isset($artist['albums'])) {
111
				$artist['albums'] = array();
112
				$artists[] = &$artist;
113
			}
114
			$album = &$allAlbumsById[$track->getAlbumId()];
115
			if (!isset($album['tracks'])) {
116
				$album['tracks'] = array();
117
				$artist['albums'][] = &$album;
118
			}
119
			try {
120
				$album['tracks'][] = $track->toCollection($this->urlGenerator, $this->userFolder);
121
			} catch (\OCP\Files\NotFoundException $e) {
1 ignored issue
show
Bug introduced by
The class OCP\Files\NotFoundException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
122
				//ignore not found	
123
			}
124
		}
125
126
		return new JSONResponse($artists);
127
	}
128
129
	/**
130
	 * @NoAdminRequired
131
	 * @NoCSRFRequired
132
	 */
133 9
	public function artists() {
134 9
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
135 9
		$includeAlbums = filter_var($this->params('albums'), FILTER_VALIDATE_BOOLEAN);
136
		/** @var Artist[] $artists */
137 9
		$artists = $this->artistBusinessLayer->findAll($this->userId);
138 9
		foreach($artists as &$artist) {
139 9
			$artist = $artist->toAPI($this->urlGenerator, $this->l10n);
140 9
			if($fulltree || $includeAlbums) {
141 6
				$artistId = $artist['id'];
142 6
				$albums = $this->albumBusinessLayer->findAllByArtist($artistId, $this->userId);
143 6
				foreach($albums as &$album) {
144 6
					$album = $album->toAPI($this->urlGenerator, $this->l10n);
145 6
					if($fulltree) {
146 3
						$albumId = $album['id'];
147 3
						$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId, $artistId);
148 3
						foreach($tracks as &$track) {
149 3
							$track = $track->toAPI($this->urlGenerator);
150 3
						}
151 3
						$album['tracks'] = $tracks;
152 3
					}
153 6
				}
154 6
				$artist['albums'] = $albums;
155 6
			}
156 9
		}
157 9
		return new JSONResponse($artists);
158
	}
159
160
	/**
161
	 * @NoAdminRequired
162
	 * @NoCSRFRequired
163
	 */
164 6 View Code Duplication
	public function artist() {
165 6
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
166 6
		$artistId = $this->getIdFromSlug($this->params('artistIdOrSlug'));
167
		/** @var Artist $artist */
168 6
		$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
169 6
		$artist = $artist->toAPI($this->urlGenerator, $this->l10n);
170 6
		if($fulltree) {
171 3
			$artistId = $artist['id'];
172 3
			$albums = $this->albumBusinessLayer->findAllByArtist($artistId, $this->userId);
173 3
			foreach($albums as &$album) {
174 3
				$album = $album->toAPI($this->urlGenerator, $this->l10n);
175 3
				$albumId = $album['id'];
176 3
				$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId, $artistId);
177 3
				foreach($tracks as &$track) {
178 3
					$track = $track->toAPI($this->urlGenerator);
179 3
				}
180 3
				$album['tracks'] = $tracks;
181 3
			}
182 3
			$artist['albums'] = $albums;
183 3
		}
184 6
		return new JSONResponse($artist);
185
	}
186
187
	/**
188
	 * @NoAdminRequired
189
	 * @NoCSRFRequired
190
	 */
191 6
	public function albums() {
192 6
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
193 6
		$albums = $this->albumBusinessLayer->findAll($this->userId);
194 6
		foreach($albums as &$album) {
195 6
			$artistIds = $album->getArtistIds();
196 6
			$album = $album->toAPI($this->urlGenerator, $this->l10n);
197 6
			if($fulltree) {
198 3
				$albumId = $album['id'];
199 3
				$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId);
200 3
				foreach($tracks as &$track) {
201 3
					$track = $track->toAPI($this->urlGenerator);
202 3
				}
203 3
				$album['tracks'] = $tracks;
204 3
				$artists = $this->artistBusinessLayer->findMultipleById($artistIds, $this->userId);
205 3
				foreach($artists as &$artist) {
206 3
					$artist = $artist->toAPI($this->urlGenerator, $this->l10n);
207 3
				}
208 3
				$album['artists'] = $artists;
209 3
			}
210 6
		}
211 6
		return new JSONResponse($albums);
212
	}
213
214
	/**
215
	 * @NoAdminRequired
216
	 * @NoCSRFRequired
217
	 */
218 6 View Code Duplication
	public function album() {
219 6
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
220 6
		$albumId = $this->getIdFromSlug($this->params('albumIdOrSlug'));
221 6
		$album = $this->albumBusinessLayer->find($albumId, $this->userId);
222
223 6
		$artistIds = $album->getArtistIds();
224 6
		$album = $album->toAPI($this->urlGenerator, $this->l10n);
225 6
		if($fulltree) {
226 3
			$albumId = $album['id'];
227 3
			$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId);
228 3
			foreach($tracks as &$track) {
229 3
				$track = $track->toAPI($this->urlGenerator);
230 3
			}
231 3
			$album['tracks'] = $tracks;
232 3
			$artists = $this->artistBusinessLayer->findMultipleById($artistIds, $this->userId);
233 3
			foreach($artists as &$artist) {
234 3
				$artist = $artist->toAPI($this->urlGenerator, $this->l10n);
235 3
			}
236 3
			$album['artists'] = $artists;
237 3
		}
238
239 6
		return new JSONResponse($album);
240
	}
241
242
	/**
243
	 * @NoAdminRequired
244
	 * @NoCSRFRequired
245
	 */
246 12
	public function tracks() {
247 12
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
248 12
		if($artistId = $this->params('artist')) {
249 3
			$tracks = $this->trackBusinessLayer->findAllByArtist($artistId, $this->userId);
250 12
		} elseif($albumId = $this->params('album')) {
251 3
			$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId);
252 3
		} else {
253 6
			$tracks = $this->trackBusinessLayer->findAll($this->userId);
254
		}
255 12
		foreach($tracks as &$track) {
256 12
			$artistId = $track->getArtistId();
257 12
			$albumId = $track->getAlbumId();
258 12
			$track = $track->toAPI($this->urlGenerator);
259 12
			if($fulltree) {
260
				/** @var Artist $artist */
261 3
				$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
262 3
				$track['artist'] = $artist->toAPI($this->urlGenerator, $this->l10n);
263 3
				$album = $this->albumBusinessLayer->find($albumId, $this->userId);
264 3
				$track['album'] = $album->toAPI($this->urlGenerator, $this->l10n);
265 3
			}
266 12
		}
267 12
		return new JSONResponse($tracks);
268
	}
269
270
	/**
271
	 * @NoAdminRequired
272
	 * @NoCSRFRequired
273
	 */
274 3
	public function track() {
275 3
		$trackId = $this->getIdFromSlug($this->params('trackIdOrSlug'));
276
		/** @var Track $track */
277 3
		$track = $this->trackBusinessLayer->find($trackId, $this->userId);
278 3
		return new JSONResponse($track->toAPI($this->urlGenerator));
279
	}
280
281
	/**
282
	 * @NoAdminRequired
283
	 * @NoCSRFRequired
284
	 */
285 3
	public function trackByFileId() {
286 3
		$fileId = $this->params('fileId');
287 3
		$track = $this->trackBusinessLayer->findByFileId($fileId, $this->userId);
288 3
		return new JSONResponse($track->toCollection($this->urlGenerator, $this->userFolder));
289
	}
290
291
	/**
292
	 * @NoAdminRequired
293
	 */
294
	public function scan() {
295
		$dry = (boolean) $this->params('dry');
296
		if($dry) {
297
			$result = array(
298
				'processed' => count($this->scanner->getScannedFiles($this->userId)),
299
				'scanned' => 0,
300
				'total' => count($this->scanner->getMusicFiles())
301
			);
302
		} else {
303
			$result = $this->scanner->rescan($this->userId);
304
		}
305
		return new JSONResponse(array($result));
306
	}
307
308
	/**
309
	 * @NoAdminRequired
310
	 * @NoCSRFRequired
311
	 */
312
	public function download() {
313
		// we no longer need the session to be kept open
314
		session_write_close();
315
316
		$fileId = $this->params('fileId');
317
318
		try {
319
			$track = $this->trackBusinessLayer->findByFileId($fileId, $this->userId);
320
		} catch(DoesNotExistException $e) {
321
			$r = new Response();
322
			$r->setStatus(Http::STATUS_NOT_FOUND);
323
			return $r;
324
		}
325
326
		$nodes = $this->userFolder->getById($track->getFileId());
327 View Code Duplication
		if(count($nodes) > 0 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
328
			// get the first valid node
329
			$node = $nodes[0];
330
331
			$mime = $node->getMimeType();
332
			$content = $node->getContent();
333
			return new FileResponse(array('mimetype' => $mime, 'content' => $content));
334
		}
335
336
		$r = new Response();
337
		$r->setStatus(Http::STATUS_NOT_FOUND);
338
		return $r;
339
	}
340
341
	/**
342
	 * @NoAdminRequired
343
	 * @NoCSRFRequired
344
	 */
345
	public function cover() {
346
		// we no longer need the session to be kept open
347
		session_write_close();
348
349
		$albumId = $this->getIdFromSlug($this->params('albumIdOrSlug'));
350
		$album = $this->albumBusinessLayer->find($albumId, $this->userId);
351
352
		$nodes = $this->userFolder->getById($album->getCoverFileId());
353 View Code Duplication
		if(count($nodes) > 0 ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
354
			// get the first valid node
355
			$node = $nodes[0];
356
357
			$mime = $node->getMimeType();
358
			$content = $node->getContent();
359
			return new FileResponse(array('mimetype' => $mime, 'content' => $content));
360
		}
361
362
		$r = new Response();
363
		$r->setStatus(Http::STATUS_NOT_FOUND);
364
		return $r;
365
	}
366
}
367