Completed
Branch master (1afb45)
by Timothy
04:13
created

Manga::map_by_status()   B

Complexity

Conditions 3
Paths 4

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
c 4
b 0
f 1
dl 0
loc 28
rs 8.8571
cc 3
eloc 17
nc 4
nop 1
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 GuzzleHttp\Cookie\SetCookie;
17
18
use Aviat\Ion\Json;
19
use Aviat\AnimeClient\Hummingbird\Transformer;
20
use Aviat\AnimeClient\Hummingbird\Enum\MangaReadingStatus;
21
22
/**
23
 * Model for handling requests dealing with the manga list
24
 */
25
class Manga extends API {
26
27
	const READING = 'Reading';
28
	const PLAN_TO_READ = 'Plan to Read';
29
	const DROPPED = 'Dropped';
30
	const ON_HOLD = 'On Hold';
31
	const COMPLETED = 'Completed';
32
33
	/**
34
	 * Map API constants to display constants
35
	 * @var array
36
	 */
37
	protected $const_map = [
38
		MangaReadingStatus::READING => self::READING,
39
		MangaReadingStatus::PLAN_TO_READ => self::PLAN_TO_READ,
40
		MangaReadingStatus::ON_HOLD => self::ON_HOLD,
41
		MangaReadingStatus::DROPPED => self::DROPPED,
42
		MangaReadingStatus::COMPLETED => self::COMPLETED
43
	];
44
45
	/**
46
	 * The base url for api requests
47
	 * @var string
48
	 */
49
	protected $base_url = "https://hummingbird.me/";
50
51
	/**
52
	 * Make an authenticated manga API call
53
	 *
54
	 * @param string $type - the HTTP verb
55
	 * @param string $url
56
	 * @param string|null $json
57
	 * @return array
58
	 */
59
	protected function _manga_api_call($type, $url, $json = NULL)
60
	{
61
		$token = $this->container->get('auth')
62
			->get_auth_token();
63
64
		// Set the token cookie, with the authentication token
65
		// from the auth class.
66
		$cookieJar = $this->cookieJar;
67
		$cookie_data = new SetCookie([
68
			'Name' => 'token',
69
			'Value' => $token,
70
			'Domain' => 'hummingbird.me'
71
		]);
72
		$cookieJar->setCookie($cookie_data);
73
74
		$config = [
75
			'cookies' => $cookieJar
76
		];
77
78
		if ( ! is_null($json))
79
		{
80
			$config['json'] = $json;
81
		}
82
83
		$result = $this->client->request(strtoupper($type), $url, $config);
84
85
		return [
86
			'statusCode' => $result->getStatusCode(),
87
			'body' => $result->getBody()
88
		];
89
	}
90
91
	/**
92
	 * Add a manga to the list
93
	 *
94
	 * @param array $data
95
	 * @return array
96
	 */
97
	public function add($data)
98
	{
99
		$object = [
100
			'manga_library_entry' => [
101
				'status' => $data['status'],
102
				'manga_id' => $data['id']
103
			]
104
		];
105
106
		return $this->_manga_api_call('post', 'manga_library_entries', $object);
0 ignored issues
show
Documentation introduced by
$object is of type array<string,array<strin...\"manga_id\":\"?\"}>"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
107
	}
108
109
	/**
110
	 * Update the selected manga
111
	 *
112
	 * @param array $data
113
	 * @return array
114
	 */
115
	public function update($data)
116
	{
117
		$id = $data['id'];
118
119
		return $this->_manga_api_call(
120
			'put',
121
			"manga_library_entries/{$id}",
122
			['manga_library_entry' => $data]
0 ignored issues
show
Documentation introduced by
array('manga_library_entry' => $data) is of type array<string,array,{"man...ibrary_entry":"array"}>, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
123
		);
124
	}
125
126
	/**
127
	 * Delete a manga entry
128
	 *
129
	 * @param  array $data
130
	 * @return array
131
	 */
132
	public function delete($data)
133
	{
134
		$id = $data['id'];
135
136
		return $this->_manga_api_call('delete', "manga_library_entries/{$id}");
137
	}
138
139
	/**
140
	 * Search for manga by name
141
	 *
142
	 * @param string $name
143
	 * @return array
144
	 * @throws RuntimeException
145
	 */
146
	public function search($name)
147
	{
148
		$logger = $this->container->getLogger('default');
149
150
		$config = [
151
			'query' => [
152
				'scope' => 'manga',
153
				'depth' => 'full',
154
				'query' => $name
155
			]
156
		];
157
158
		$response = $this->get('search.json', $config);
159
160 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...
161
		{
162
			$logger->warning("Non 200 response for search api call");
163
			$logger->warning($response->getBody());
164
165
			throw new RuntimeException($response->getEffectiveUrl());
166
		}
167
168
		return Json::decode($response->getBody(), TRUE);
169
	}
170
171
	/**
172
	 * Get a category out of the full list
173
	 *
174
	 * @param string $status
175
	 * @return array
176
	 */
177
	public function get_list($status)
178
	{
179
		$data = $this->cache->get($this, '_get_list_from_api');
180
		return ($status !== 'All') ? $data[$status] : $data;
181
	}
182
183
	/**
184
	 * Retrieve the list from the hummingbird api
185
	 *
186
	 * @param  string $status
187
	 * @return array
188
	 */
189
	public function _get_list_from_api($status = "All")
190
	{
191
		$config = [
192
			'query' => [
193
				'user_id' => $this->config->get('hummingbird_username')
194
			],
195
			'allow_redirects' => FALSE
196
		];
197
198
		$response = $this->get('manga_library_entries', $config);
199
		$data = $this->transform($response);
200
		$final = $this->map_by_status($data);
201
		return ($status !== 'All') ? $final[$status] : $final;
202
	}
203
204
	/**
205
	 * Transform the response to be more consistent
206
	 *
207
	 * @param \GuzzleHttp\Message\Response $response
208
	 * @codeCoverageIgnore
209
	 * @return array
210
	 */
211
	private function transform($response)
212
	{
213
		// Bail out early if there isn't any manga data
214
		$api_data = Json::decode($response->getBody(), TRUE);
215
		if ( ! array_key_exists('manga', $api_data))
216
		{
217
			return [];
218
		}
219
220
		$zippered_data = $this->zipper_lists($api_data);
221
		$transformer = new Transformer\MangaListTransformer();
222
		$transformed_data = $transformer->transform_collection($zippered_data);
223
224
		return $transformed_data;
225
	}
226
227
	/**
228
	 * Get the details of a manga
229
	 *
230
	 * @param string $manga_id
231
	 * @return array
232
	 */
233
	public function get_manga($manga_id)
234
	{
235
		$raw = $this->_manga_api_call('get', "manga/{$manga_id}.json");
236
		return Json::decode($raw['body'], TRUE);
237
	}
238
239
	/**
240
	 * Map transformed anime data to be organized by reading status
241
	 *
242
	 * @param array $data
243
	 * @return array
244
	 */
245
	private function map_by_status($data)
246
	{
247
		$output = [
248
			self::READING => [],
249
			self::PLAN_TO_READ => [],
250
			self::ON_HOLD => [],
251
			self::DROPPED => [],
252
			self::COMPLETED => [],
253
		];
254
255
		foreach ($data as &$entry)
256
		{
257
			$entry['manga']['image'] = $this->get_cached_image(
258
				$entry['manga']['image'],
259
				$entry['manga']['slug'],
260
				'manga'
261
			);
262
			$key = $this->const_map[$entry['reading_status']];
263
			$output[$key][] = $entry;
264
		}
265
266
		foreach($output as &$val)
267
		{
268
			$this->sort_by_name($val, 'manga');
269
		}
270
271
		return $output;
272
	}
273
274
	/**
275
	 * Combine the two manga lists into one
276
	 * @param  array $raw_data
277
	 * @return array
278
	 */
279
	private function zipper_lists($raw_data)
280
	{
281
		return (new Transformer\MangaListsZipper($raw_data))->transform();
282
	}
283
}
284
// End of MangaModel.php