Completed
Push — develop ( 93b885...6555aa )
by Timothy
02:26
created

Anime   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 245
Duplicated Lines 24.08 %

Coupling/Cohesion

Components 2
Dependencies 5

Importance

Changes 17
Bugs 5 Features 3
Metric Value
wmc 21
c 17
b 5
f 3
lcom 2
cbo 5
dl 59
loc 245
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A update() 20 20 3
A delete() 20 20 3
B get_all_lists() 0 25 3
A get_list() 0 10 1
A get_anime() 0 12 1
A search() 7 22 2
B _get_list_from_api() 0 28 4
B _check_cache() 12 23 4

How to fix   Duplicated Code   

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:

1
<?php
2
/**
3
 * Hummingbird Anime Client
4
 *
5
 * An API client for Hummingbird to manage anime and manga watch lists
6
 *
7
 * @package     HummingbirdAnimeClient
8
 * @author      Timothy J. Warren
9
 * @copyright   Copyright (c) 2015 - 2016
10
 * @link        https://github.com/timw4mail/HummingBirdAnimeClient
11
 * @license     MIT
12
 */
13
14
namespace Aviat\AnimeClient\Model;
15
16
use Aviat\Ion\Json;
17
use Aviat\AnimeClient\Hummingbird\Enum\AnimeWatchingStatus;
18
use Aviat\AnimeClient\Hummingbird\Transformer\AnimeListTransformer;
19
20
/**
21
 * Model for handling requests dealing with the anime list
22
 */
23
class Anime extends API {
24
25
	// Display constants
26
	const WATCHING = 'Watching';
27
	const PLAN_TO_WATCH = 'Plan to Watch';
28
	const DROPPED = 'Dropped';
29
	const ON_HOLD = 'On Hold';
30
	const COMPLETED = 'Completed';
31
32
	/**
33
	 * The base url for api requests
34
	 * @var string $base_url
35
	 */
36
	protected $base_url = "https://hummingbird.me/api/v1/";
37
38
	/**
39
	 * Map of API status constants to display constants
40
	 * @var array
41
	 */
42
	protected $const_map = [
43
		AnimeWatchingStatus::WATCHING => self::WATCHING,
44
		AnimeWatchingStatus::PLAN_TO_WATCH => self::PLAN_TO_WATCH,
45
		AnimeWatchingStatus::ON_HOLD => self::ON_HOLD,
46
		AnimeWatchingStatus::DROPPED => self::DROPPED,
47
		AnimeWatchingStatus::COMPLETED => self::COMPLETED,
48
	];
49
50
	/**
51
	 * Update the selected anime
52
	 *
53
	 * @param array $data
54
	 * @return array|false
55
	 */
56 View Code Duplication
	public function update($data)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
57
	{
58
		$auth = $this->container->get('auth');
59
		if ( ! $auth->is_authenticated() || ! array_key_exists('id', $data))
60
		{
61
			return FALSE;
62
		}
63
64
		$id = $data['id'];
65
		$data['auth_token'] = $auth->get_auth_token();
66
67
		$response = $this->client->post("libraries/{$id}", [
68
			'form_params' => $data
69
		]);
70
71
		return [
72
			'statusCode' => $response->getStatusCode(),
73
			'body' => Json::decode($response->getBody(), TRUE)
74
		];
75
	}
76
77
	/**
78
	 * Remove an anime from a list
79
	 *
80
	 * @param  array $data
81
	 * @return array
0 ignored issues
show
Documentation introduced by
Should the return type not be false|array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
82
	 */
83 View Code Duplication
	public function delete($data)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
84
	{
85
		$auth = $this->container->get('auth');
86
		if ( ! $auth->is_authenticated() || ! array_key_exists('id', $data))
87
		{
88
			return FALSE;
89
		}
90
91
		$id = $data['id'];
92
		$data['auth_token'] = $auth->get_auth_token();
93
94
		$response = $this->client->post("libraries/{$id}/remove", [
95
			'form_params' => $data
96
		]);
97
98
		return [
99
			'statusCode' => $response->getStatusCode(),
100
			'body' => Json::decode($response->getBody(), TRUE)
101
		];
102
	}
103
104
	/**
105
	 * Get the full set of anime lists
106
	 *
107
	 * @return array
108
	 */
109
	public function get_all_lists()
110
	{
111
		$output = [
112
			self::WATCHING => [],
113
			self::PLAN_TO_WATCH => [],
114
			self::ON_HOLD => [],
115
			self::DROPPED => [],
116
			self::COMPLETED => [],
117
		];
118
119
		$data = $this->_get_list_from_api();
120
121
		foreach ($data as $datum)
122
		{
123
			$output[$this->const_map[$datum['watching_status']]][] = $datum;
124
		}
125
126
		// Sort anime by name
127
		foreach ($output as &$status_list)
128
		{
129
			$this->sort_by_name($status_list, 'anime');
130
		}
131
132
		return $output;
133
	}
134
135
	/**
136
	 * Get a category out of the full list
137
	 *
138
	 * @param string $status
139
	 * @return array
140
	 */
141
	public function get_list($status)
142
	{
143
		$data = $this->_get_list_from_api($status);
144
		$this->sort_by_name($data, 'anime');
145
146
		$output = [];
147
		$output[$this->const_map[$status]] = $data;
148
149
		return $output;
150
	}
151
152
	/**
153
	 * Get information about an anime from its id
154
	 *
155
	 * @param string $anime_id
156
	 * @return array
157
	 */
158
	public function get_anime($anime_id)
159
	{
160
		$config = [
161
			'query' => [
162
				'id' => $anime_id
163
			]
164
		];
165
166
		$response = $this->client->get("anime/{$anime_id}", $config);
167
168
		return Json::decode($response->getBody(), TRUE);
169
	}
170
171
	/**
172
	 * Search for anime by name
173
	 *
174
	 * @param string $name
175
	 * @return array
176
	 */
177
	public function search($name)
178
	{
179
		$logger = $this->container->getLogger('default');
180
181
		$config = [
182
			'query' => [
183
				'query' => $name
184
			]
185
		];
186
187
		$response = $this->get('search/anime', $config);
188
189 View Code Duplication
		if ($response->getStatusCode() != 200)
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...
190
		{
191
			$logger->warning("Non 200 response for search api call");
192
			$logger->warning($response->getBody());
193
194
			throw new RuntimeException($response->getEffectiveUrl());
195
		}
196
197
		return Json::decode($response->getBody(), TRUE);
198
	}
199
200
	/**
201
	 * Retrieve data from the api
202
	 *
203
	 * @codeCoverageIgnore
204
	 * @param string $status
205
	 * @return array
206
	 */
207
	protected function _get_list_from_api($status = "all")
208
	{
209
		$config = [
210
			'allow_redirects' => FALSE
211
		];
212
213
		if ($status != "all")
214
		{
215
			$config['query']['status'] = $status;
216
		}
217
218
		$username = $this->config->get('hummingbird_username');
219
		$auth = $this->container->get('auth');
220
		if ($auth->is_authenticated())
221
		{
222
			$config['query']['auth_token'] = $auth->get_auth_token();
223
		}
224
225
		$response = $this->get("users/{$username}/library", $config);
226
		$output = $this->_check_cache($status, $response);
227
228
		foreach ($output as &$row)
229
		{
230
			$row['anime']['image'] = $this->get_cached_image($row['anime']['image'], $row['anime']['slug'], 'anime');
231
		}
232
233
		return $output;
234
	}
235
236
	/**
237
	 * Handle caching of transformed api data
238
	 *
239
	 * @codeCoverageIgnore
240
	 * @param string $status
241
	 * @param \GuzzleHttp\Message\Response
242
	 * @return array
243
	 */
244
	protected function _check_cache($status, $response)
245
	{
246
		$cache_file = _dir($this->config->get('data_cache_path'), "anime-{$status}.json");
247
		$transformed_cache_file = _dir($this->config->get('data_cache_path'), "anime-{$status}-transformed.json");
248
249
		$cached = (file_exists($cache_file))
250
			? Json::decodeFile($cache_file)
251
			: [];
252
		$api_data = Json::decode($response->getBody(), TRUE);
253
254 View Code Duplication
		if ($api_data === $cached && file_exists($transformed_cache_file))
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...
255
		{
256
			return Json::decodeFile($transformed_cache_file);
257
		}
258
		else
259
		{
260
			Json::encodeFile($cache_file, $api_data);
261
			$transformer = new AnimeListTransformer();
262
			$transformed = $transformer->transform_collection($api_data);
263
			Json::encodeFile($transformed_cache_file, $transformed);
264
			return $transformed;
265
		}
266
	}
267
}
268
// End of AnimeModel.php