Completed
Push — master ( 5e0489...1b8ed5 )
by Timothy
02:40
created

AnimeCollection::get()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 8
rs 9.4286
cc 1
eloc 5
nc 1
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
10
 * @link        https://github.com/timw4mail/HummingBirdAnimeClient
11
 * @license     MIT
12
 */
13
14
namespace Aviat\AnimeClient\Model;
15
16
use Aviat\Ion\Di\ContainerInterface;
17
use Aviat\AnimeClient\Model\Anime as AnimeModel;
18
19
/**
20
 * Model for getting anime collection data
21
 */
22
class AnimeCollection extends DB {
23
24
	/**
25
	 * Anime API Model
26
	 * @var object $anime_model
27
	 */
28
	private $anime_model;
29
30
	/**
31
	 * Whether the database is valid for querying
32
	 * @var bool
33
	 */
34
	private $valid_database = FALSE;
35
36
	/**
37
	 * Constructor
38
	 *
39
	 * @param ContainerInterface $container
40
	 */
41
	public function __construct(ContainerInterface $container)
42
	{
43
		parent::__construct($container);
44
45
		try
46
		{
47
			$this->db = \Query($this->db_config['collection']);
48
		}
49
		catch (\PDOException $e)
50
		{
51
			$this->valid_database = FALSE;
52
			return FALSE;
53
		}
54
		$this->anime_model = $container->get('anime-model');
55
56
		// Is database valid? If not, set a flag so the
57
		// app can be run without a valid database
58
		$db_file_name = $this->db_config['collection']['file'];
59
		if ($db_file_name !== ':memory:')
60
		{
61
			if (file_exists($db_file_name))
62
			{
63
				$db_file = file_get_contents($db_file_name);
64
				$this->valid_database = (strpos($db_file, 'SQLite format 3') === 0);
65
			}
66
			else
67
			{
68
				$this->valid_database = FALSE;
69
			}
70
		}
71
		else
72
		{
73
			$this->valid_database = TRUE;
74
		}
75
76
		// Do an import if an import file exists
77
		$this->json_import();
78
	}
79
80
	/**
81
	 * Get genres for anime collection items
82
	 *
83
	 * @param array $filter
84
	 * @return array
85
	 */
86
	public function get_genre_list($filter = [])
87
	{
88
		$this->db->select('hummingbird_id, genre')
89
			->from('genre_anime_set_link gl')
90
			->join('genres g', 'g.id=gl.genre_id', 'left');
91
92
93
		if ( ! empty($filter))
94
		{
95
			$this->db->where_in('hummingbird_id', $filter);
96
		}
97
98
		$query = $this->db->order_by('hummingbird_id')
99
			->order_by('genre')
100
			->get();
101
102
		$output = [];
103
104
		foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $row)
105
		{
106
			$id = $row['hummingbird_id'];
107
			$genre = $row['genre'];
108
109
			// Empty genre names aren't useful
110
			if (empty($genre))
111
			{
112
				continue;
113
			}
114
115
			if (array_key_exists($id, $output))
116
			{
117
				array_push($output[$id], $genre);
118
			}
119
			else
120
			{
121
				$output[$id] = [$genre];
122
			}
123
		}
124
125
		return $output;
126
	}
127
128
	/**
129
	 * Get collection from the database, and organize by media type
130
	 *
131
	 * @return array
132
	 */
133
	public function get_collection()
134
	{
135
		$raw_collection = $this->_get_collection();
136
137
		$collection = [];
138
139
		foreach ($raw_collection as $row)
140
		{
141
			if (array_key_exists($row['media'], $collection))
142
			{
143
				$collection[$row['media']][] = $row;
144
			}
145
			else
146
			{
147
				$collection[$row['media']] = [$row];
148
			}
149
		}
150
151
		return $collection;
152
	}
153
154
	/**
155
	 * Get list of media types
156
	 *
157
	 * @return array
158
	 */
159
	public function get_media_type_list()
160
	{
161
		$output = array();
162
163
		$query = $this->db->select('id, type')
164
			->from('media')
165
			->get();
166
167
		foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $row)
168
		{
169
			$output[$row['id']] = $row['type'];
170
		}
171
172
		return $output;
173
	}
174
175
	/**
176
	 * Get item from collection for editing
177
	 *
178
	 * @param int $id
179
	 * @return array
180
	 */
181
	public function get_collection_entry($id)
182
	{
183
		$query = $this->db->from('anime_set')
184
			->where('hummingbird_id', (int)$id)
185
			->get();
186
187
		return $query->fetch(\PDO::FETCH_ASSOC);
188
	}
189
190
	/**
191
	 * Get full collection from the database
192
	 *
193
	 * @return array
194
	 */
195
	private function _get_collection()
196
	{
197
		if ( ! $this->valid_database)
198
		{
199
			return [];
200
		}
201
202
		$query = $this->db->select('hummingbird_id, slug, title, alternate_title, show_type,
203
			 age_rating, episode_count, episode_length, cover_image, notes, media.type as media')
204
			->from('anime_set a')
205
			->join('media', 'media.id=a.media_id', 'inner')
206
			->order_by('media')
207
			->order_by('title')
208
			->get();
209
210
		return $query->fetchAll(\PDO::FETCH_ASSOC);
211
	}
212
213
	/**
214
	 * Add an item to the anime collection
215
	 *
216
	 * @param array $data
217
	 * @return void
218
	 */
219
	public function add($data)
220
	{
221
		$anime = (object)$this->anime_model->get_anime($data['id']);
222
223
		$this->db->set([
224
			'hummingbird_id' => $data['id'],
225
			'slug' => $anime->slug,
226
			'title' => $anime->title,
227
			'alternate_title' => $anime->alternate_title,
228
			'show_type' => $anime->show_type,
229
			'age_rating' => $anime->age_rating,
230
			'cover_image' => basename(
231
				$this->get_cached_image($anime->cover_image, $anime->slug, 'anime')
232
			),
233
			'episode_count' => $anime->episode_count,
234
			'episode_length' => $anime->episode_length,
235
			'media_id' => $data['media_id'],
236
			'notes' => $data['notes']
237
		])->insert('anime_set');
238
239
		$this->update_genre($data['id']);
240
	}
241
242
	/**
243
	 * Update a collection item
244
	 *
245
	 * @param array $data
246
	 * @return void
247
	 */
248
	public function update($data)
249
	{
250
		// If there's no id to update, don't update
251
		if ( ! array_key_exists('hummingbird_id', $data))
252
		{
253
			return;
254
		}
255
256
		$id = $data['hummingbird_id'];
257
		unset($data['hummingbird_id']);
258
259
		$this->db->set($data)
260
			->where('hummingbird_id', $id)
261
			->update('anime_set');
262
	}
263
264
	/**
265
	 * Remove a colleciton item
266
	 * @param  array $data
267
	 * @return void
268
	 */
269
	public function delete($data)
270
	{
271
		// If there's no id to update, don't delete
272
		if ( ! array_key_exists('hummingbird_id', $data))
273
		{
274
			return;
275
		}
276
277
		$this->db->where('hummingbird_id', $data['hummingbird_id'])
278
			->delete('anime_set');
279
	}
280
281
	/**
282
	 * Get the details of a collection item
283
	 *
284
	 * @param int $hummingbird_id
285
	 * @return array
286
	 */
287
	public function get($hummingbird_id)
288
	{
289
		$query = $this->db->from('anime_set')
290
			->where('hummingbird_id', $hummingbird_id)
291
			->get();
292
293
		return $query->fetch(\PDO::FETCH_ASSOC);
294
	}
295
296
	/**
297
	 * Import anime into collection from a json file
298
	 *
299
	 * @return void
300
	 */
301
	private function json_import()
302
	{
303
		if ( ! file_exists('import.json') || ! $this->valid_database)
304
		{
305
			return;
306
		}
307
308
		$anime = json_decode(file_get_contents("import.json"));
309
310
		foreach ($anime as $item)
311
		{
312
			$this->db->set([
313
				'hummingbird_id' => $item->id,
314
				'slug' => $item->slug,
315
				'title' => $item->title,
316
				'alternate_title' => $item->alternate_title,
317
				'show_type' => $item->show_type,
318
				'age_rating' => $item->age_rating,
319
				'cover_image' => basename(
320
					$this->get_cached_image($item->cover_image, $item->slug, 'anime')
321
				),
322
				'episode_count' => $item->episode_count,
323
				'episode_length' => $item->episode_length
324
			])->insert('anime_set');
325
		}
326
327
		// Delete the import file
328
		unlink('import.json');
329
330
		// Update genre info
331
		$this->update_genres();
332
	}
333
334
	/**
335
	 * Update genre information for selected anime
336
	 *
337
	 * @param int $anime_id The current anime
338
	 * @return void
339
	 */
340
	private function update_genre($anime_id)
341
	{
342
		$genre_info = $this->get_genre_data();
343
		extract($genre_info);
344
345
		// Get api information
346
		$anime = $this->anime_model->get_anime($anime_id);
347
348
		foreach ($anime['genres'] as $genre)
349
		{
350
			// Add genres that don't currently exist
351
			if ( ! in_array($genre['name'], $genres))
352
			{
353
				$this->db->set('genre', $genre['name'])
354
					->insert('genres');
355
356
				$genres[] = $genre['name'];
357
			}
358
359
			// Update link table
360
			// Get id of genre to put in link table
361
			$flipped_genres = array_flip($genres);
362
363
			$insert_array = [
364
				'hummingbird_id' => $anime['id'],
365
				'genre_id' => $flipped_genres[$genre['name']]
366
			];
367
368
			if (array_key_exists($anime['id'], $links))
369
			{
370
				if ( ! in_array($flipped_genres[$genre['name']], $links[$anime['id']]))
371
				{
372
					$this->db->set($insert_array)->insert('genre_anime_set_link');
373
				}
374
			}
375
			else
376
			{
377
				$this->db->set($insert_array)->insert('genre_anime_set_link');
378
			}
379
		}
380
	}
381
382
	/**
383
	 * Get list of existing genres
384
	 *
385
	 * @return array
386
	 */
387
	private function get_genre_data()
388
	{
389
		$genres = [];
390
		$links = [];
391
392
		// Get existing genres
393
		$query = $this->db->select('id, genre')
394
			->from('genres')
395
			->get();
396
		foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $genre)
397
		{
398
			$genres[$genre['id']] = $genre['genre'];
399
		}
400
401
		// Get existing link table entries
402
		$query = $this->db->select('hummingbird_id, genre_id')
403
			->from('genre_anime_set_link')
404
			->get();
405
		foreach ($query->fetchAll(\PDO::FETCH_ASSOC) as $link)
406
		{
407
			if (array_key_exists($link['hummingbird_id'], $links))
408
			{
409
				$links[$link['hummingbird_id']][] = $link['genre_id'];
410
			}
411
			else
412
			{
413
				$links[$link['hummingbird_id']] = [$link['genre_id']];
414
			}
415
		}
416
417
		return [
418
			'genres' => $genres,
419
			'links' => $links
420
		];
421
	}
422
423
	/**
424
	 * Update genre information for the entire collection
425
	 *
426
	 * @return void
427
	 */
428
	private function update_genres()
429
	{
430
		// Get the anime collection
431
		$collection = $this->_get_collection();
432
		foreach ($collection as $anime)
433
		{
434
			// Get api information
435
			$this->update_genre($anime['hummingbird_id']);
436
		}
437
	}
438
}
439
// End of AnimeCollectionModel.php