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

Manga::_manga_api_call()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 31
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 31
rs 8.8571
cc 2
eloc 17
nc 2
nop 3
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\Cookiejar;
17
use GuzzleHttp\Cookie\SetCookie;
18
19
use Aviat\Ion\Json;
20
use Aviat\AnimeClient\Model\API;
21
use Aviat\AnimeClient\Hummingbird\Transformer;
22
use Aviat\AnimeClient\Hummingbird\Enum\MangaReadingStatus;
23
24
/**
25
 * Model for handling requests dealing with the manga list
26
 */
27
class Manga extends API {
28
29
	const READING = 'Reading';
30
	const PLAN_TO_READ = 'Plan to Read';
31
	const DROPPED = 'Dropped';
32
	const ON_HOLD = 'On Hold';
33
	const COMPLETED = 'Completed';
34
35
	/**
36
	 * Map API constants to display constants
37
	 * @var array
38
	 */
39
	protected $const_map = [
40
		MangaReadingStatus::READING => self::READING,
41
		MangaReadingStatus::PLAN_TO_READ => self::PLAN_TO_READ,
42
		MangaReadingStatus::ON_HOLD => self::ON_HOLD,
43
		MangaReadingStatus::DROPPED => self::DROPPED,
44
		MangaReadingStatus::COMPLETED => self::COMPLETED
45
	];
46
47
	/**
48
	 * The base url for api requests
49
	 * @var string
50
	 */
51
	protected $base_url = "https://hummingbird.me/";
52
53
	protected function _manga_api_call($type, $url, $json=null)
54
	{
55
		$token = $this->container->get('auth')
56
			->get_auth_token();
57
58
		// Set the token cookie, with the authentication token
59
		// from the auth class.
60
		$cookieJar = $this->cookieJar;
61
		$cookie_data = new SetCookie([
62
			'Name' => 'token',
63
			'Value' => $token,
64
			'Domain' => 'hummingbird.me'
65
		]);
66
		$cookieJar->setCookie($cookie_data);
67
68
		$config = [
69
			'cookies' => $cookieJar
70
		];
71
72
		if ( ! is_null($json))
73
		{
74
			$config['json'] = $json;
75
		}
76
77
		$result = $this->client->request(strtoupper($type), $url, $config);
78
79
		return [
80
			'statusCode' => $result->getStatusCode(),
81
			'body' => $result->getBody()
82
		];
83
	}
84
85
	/**
86
	 * Add a manga to the list
87
	 *
88
	 * @param array $data
89
	 */
90
	public function add($data)
91
	{
92
		$object = [
93
			'manga_library_entry' => [
94
				'status' => $data['status'],
95
				'manga_id' => $data['id']
96
			]
97
		];
98
99
		return $this->_manga_api_call('post', 'manga_library_entries', $object);
100
	}
101
102
	/**
103
	 * Update the selected manga
104
	 *
105
	 * @param array $data
106
	 * @return array
107
	 */
108
	public function update($data)
109
	{
110
		$id = $data['id'];
111
112
		return $this->_manga_api_call(
113
			'put',
114
			"manga_library_entries/{$id}",
115
			['manga_library_entry' => $data]
116
		);
117
	}
118
119
	/**
120
	 * Delete a manga entry
121
	 *
122
	 * @param  array $data
123
	 * @return array
124
	 */
125
	public function delete($data)
126
	{
127
		$id = $data['id'];
128
129
		return $this->_manga_api_call('delete', "manga_library_entries/{$id}");
130
	}
131
132
	/**
133
	 * Search for manga by name
134
	 *
135
	 * @param string $name
136
	 * @return array
137
	 */
138
	public function search($name)
139
	{
140
		$logger = $this->container->getLogger('default');
141
142
		$config = [
143
			'query' => [
144
				'scope' => 'manga',
145
				'depth' => 'full',
146
				'query' => $name
147
			]
148
		];
149
150
		$response = $this->get('search.json', $config);
151
152 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...
153
		{
154
			$logger->warning("Non 200 response for search api call");
155
			$logger->warning($response->getBody());
156
157
			throw new RuntimeException($response->getEffectiveUrl());
158
		}
159
160
		return Json::decode($response->getBody(), TRUE);
161
	}
162
163
	/**
164
	 * Get the full set of anime lists
165
	 *
166
	 * @return array
167
	 */
168
	public function get_all_lists()
169
	{
170
		$data = $this->_get_list_from_api();
171
172
		foreach ($data as &$val)
173
		{
174
			$this->sort_by_name($val, 'manga');
175
		}
176
177
		return $data;
178
	}
179
180
	/**
181
	 * Get a category out of the full list
182
	 *
183
	 * @param string $status
184
	 * @return array
185
	 */
186
	public function get_list($status)
187
	{
188
		$data = $this->_get_list_from_api($status);
189
		$this->sort_by_name($data, 'manga');
190
191
		return $data;
192
	}
193
194
	/**
195
	 * Retrieve the list from the hummingbird api
196
	 *
197
	 * @param  string $status
198
	 * @return array
199
	 */
200
	protected function _get_list_from_api($status = "All")
201
	{
202
		$config = [
203
			'query' => [
204
				'user_id' => $this->config->get('hummingbird_username')
205
			],
206
			'allow_redirects' => FALSE
207
		];
208
209
		$response = $this->get('manga_library_entries', $config);
210
		$data = $this->_check_cache($response);
211
		$output = $this->map_by_status($data);
212
213
		return (array_key_exists($status, $output))
214
			? $output[$status]
215
			: $output;
216
	}
217
218
	/**
219
	 * Check the status of the cache and return the appropriate response
220
	 *
221
	 * @param \GuzzleHttp\Message\Response $response
222
	 * @codeCoverageIgnore
223
	 * @return array
224
	 */
225
	private function _check_cache($response)
226
	{
227
		// Bail out early if there isn't any manga data
228
		$api_data = Json::decode($response->getBody(), TRUE);
229
		if ( ! array_key_exists('manga', $api_data))
230
		{
231
			return [];
232
		}
233
234
		$cache_file = _dir($this->config->get('data_cache_path'), 'manga.json');
235
		$transformed_cache_file = _dir(
236
			$this->config->get('data_cache_path'),
237
			'manga-transformed.json'
238
		);
239
240
		$cached_data = file_exists($cache_file)
241
			? Json::decodeFile($cache_file)
242
			: [];
243
244 View Code Duplication
		if ($cached_data === $api_data && 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...
245
		{
246
			return Json::decodeFile($transformed_cache_file);
247
		}
248
		else
249
		{
250
			Json::encodeFile($cache_file, $api_data);
251
252
			$zippered_data = $this->zipper_lists($api_data);
253
			$transformer = new Transformer\MangaListTransformer();
254
			$transformed_data = $transformer->transform_collection($zippered_data);
255
			Json::encodeFile($transformed_cache_file, $transformed_data);
256
			return $transformed_data;
257
		}
258
	}
259
260
	/**
261
	 * Map transformed anime data to be organized by reading status
262
	 *
263
	 * @param array $data
264
	 * @return array
265
	 */
266
	private function map_by_status($data)
267
	{
268
		$output = [
269
			self::READING => [],
270
			self::PLAN_TO_READ => [],
271
			self::ON_HOLD => [],
272
			self::DROPPED => [],
273
			self::COMPLETED => [],
274
		];
275
276
		foreach ($data as &$entry)
277
		{
278
			$entry['manga']['image'] = $this->get_cached_image(
279
				$entry['manga']['image'],
280
				$entry['manga']['slug'],
281
				'manga'
282
			);
283
			$key = $this->const_map[$entry['reading_status']];
284
			$output[$key][] = $entry;
285
		}
286
287
		return $output;
288
	}
289
290
	/**
291
	 * Combine the two manga lists into one
292
	 * @param  array $raw_data
293
	 * @return array
294
	 */
295
	private function zipper_lists($raw_data)
296
	{
297
		return (new Transformer\MangaListsZipper($raw_data))->transform();
298
	}
299
}
300
// End of MangaModel.php