Browse Source

Some minor code cleanliness refactoring

Timothy J. Warren 3 months ago
parent
commit
f04cc7d1d5
57 changed files with 429 additions and 149 deletions
  1. 2
    2
      app/views/anime/cover.php
  2. 1
    1
      app/views/anime/details.php
  3. 1
    1
      app/views/anime/edit.php
  4. 7
    7
      app/views/anime/list.php
  5. 1
    0
      composer.json
  6. 1
    1
      src/API/Enum/AnimeWatchingStatus/Kitsu.php
  7. 1
    1
      src/API/Enum/AnimeWatchingStatus/MAL.php
  8. 1
    1
      src/API/Enum/AnimeWatchingStatus/Route.php
  9. 1
    1
      src/API/Enum/AnimeWatchingStatus/Title.php
  10. 1
    1
      src/API/Enum/MangaReadingStatus/Kitsu.php
  11. 1
    1
      src/API/Enum/MangaReadingStatus/MAL.php
  12. 2
    2
      src/API/Enum/MangaReadingStatus/Route.php
  13. 2
    2
      src/API/Enum/MangaReadingStatus/Title.php
  14. 1
    1
      src/API/JsonAPI.php
  15. 1
    1
      src/API/Kitsu.php
  16. 3
    3
      src/API/Kitsu/Auth.php
  17. 1
    1
      src/API/Kitsu/Enum/AnimeAiringStatus.php
  18. 1
    1
      src/API/Kitsu/KitsuRequestBuilder.php
  19. 24
    25
      src/API/Kitsu/ListItem.php
  20. 21
    16
      src/API/Kitsu/Model.php
  21. 26
    17
      src/API/Kitsu/Transformer/AnimeListTransformer.php
  22. 8
    7
      src/API/Kitsu/Transformer/AnimeTransformer.php
  23. 1
    1
      src/API/Kitsu/Transformer/MangaListTransformer.php
  24. 1
    1
      src/API/Kitsu/Transformer/MangaTransformer.php
  25. 3
    2
      src/API/ListItemInterface.php
  26. 1
    1
      src/API/MAL.php
  27. 4
    3
      src/API/MAL/ListItem.php
  28. 1
    1
      src/API/MAL/MALRequestBuilder.php
  29. 4
    3
      src/API/MAL/Model.php
  30. 8
    9
      src/API/MAL/Transformer/AnimeListTransformer.php
  31. 1
    1
      src/API/MAL/Transformer/MangaListTransformer.php
  32. 1
    1
      src/API/Mapping/AnimeWatchingStatus.php
  33. 1
    1
      src/API/Mapping/MangaReadingStatus.php
  34. 3
    5
      src/API/ParallelAPIRequest.php
  35. 1
    1
      src/API/XML.php
  36. 1
    1
      src/Command/CacheClear.php
  37. 1
    1
      src/Command/CachePrime.php
  38. 1
    1
      src/Command/SyncLists.php
  39. 3
    3
      src/Controller/Anime.php
  40. 1
    1
      src/Controller/AnimeCollection.php
  41. 1
    1
      src/Controller/Character.php
  42. 1
    1
      src/Controller/Index.php
  43. 1
    1
      src/Controller/Manga.php
  44. 1
    1
      src/Controller/MangaCollection.php
  45. 1
    1
      src/Dispatcher.php
  46. 3
    2
      src/Helper/Menu.php
  47. 1
    1
      src/MenuGenerator.php
  48. 1
    1
      src/Model/API.php
  49. 12
    7
      src/Model/Anime.php
  50. 1
    1
      src/Model/AnimeCollection.php
  51. 1
    1
      src/Model/Manga.php
  52. 1
    1
      src/Model/MangaCollection.php
  53. 121
    0
      src/Types/AbstractType.php
  54. 40
    0
      src/Types/Anime.php
  55. 26
    0
      src/Types/AnimeFormItem.php
  56. 30
    0
      src/Types/AnimeFormItemData.php
  57. 42
    0
      src/Types/AnimeListItem.php

+ 2
- 2
app/views/anime/cover.php View File

@@ -24,7 +24,7 @@
24 24
 					<img src="<?= $urlGenerator->assetUrl("images/anime/{$item['anime']['id']}.jpg") ?>" alt="" />
25 25
 					<div class="name">
26 26
 						<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]); ?>">
27
-							<?= array_shift($item['anime']['titles']) ?>
27
+							<?= $item['anime']['title'] ?>
28 28
 							<?php foreach ($item['anime']['titles'] as $title): ?>
29 29
 								<br /><small><?= $title ?></small>
30 30
 							<?php endforeach ?>
@@ -85,7 +85,7 @@
85 85
 							</div>
86 86
 						</div>
87 87
 						<div class="row">
88
-							<div class="media_type"><?= $escape->html($item['anime']['type']) ?></div>
88
+							<div class="media_type"><?= $escape->html($item['anime']['show_type']) ?></div>
89 89
 							<div class="airing_status"><?= $escape->html($item['airing']['status']) ?></div>
90 90
 							<div class="age_rating"><?= $escape->html($item['anime']['age_rating']) ?></div>
91 91
 						</div>

+ 1
- 1
app/views/anime/details.php View File

@@ -38,7 +38,7 @@
38 38
 			</table>
39 39
 		</div>
40 40
 		<div>
41
-			<h2><a rel="external" href="<?= $show_data['url'] ?>"><?= array_shift($show_data['titles']) ?></a></h2>
41
+			<h2><a rel="external" href="<?= $show_data['url'] ?>"><?= $show_data['title'] ?></a></h2>
42 42
             <?php foreach ($show_data['titles'] as $title): ?>
43 43
                 <h3><?= $title ?></h3>
44 44
             <?php endforeach ?>

+ 1
- 1
app/views/anime/edit.php View File

@@ -6,7 +6,7 @@
6 6
 				<thead>
7 7
 					<tr>
8 8
 						<th>
9
-							<h3><?= $escape->html(array_shift($item['anime']['titles'])) ?></h3>
9
+							<h3><?= $escape->html($item['anime']['title']) ?></h3>
10 10
 							<?php foreach($item['anime']['titles'] as $title): ?>
11 11
 							<h4><?= $escape->html($title) ?></h4>
12 12
 							<?php endforeach ?>

+ 7
- 7
app/views/anime/list.php View File

@@ -42,15 +42,15 @@
42 42
 					<?php endif ?>
43 43
 					<td class="justify">
44 44
 						<a href="<?= $url->generate('anime.details', ['id' => $item['anime']['slug']]) ?>">
45
-							<?= array_shift($item['anime']['titles']) ?>
45
+							<?= $item['anime']['title'] ?>
46 46
 						</a>
47
-	                    <?php foreach($item['anime']['titles'] as $title): ?>
48
-	                        <br /><?= $title ?>
49
-	                    <?php endforeach ?>
47
+						<?php foreach ($item['anime']['titles'] as $title): ?>
48
+							<br/><?= $title ?>
49
+						<?php endforeach ?>
50 50
 					</td>
51 51
 					<td><?= $item['airing']['status'] ?></td>
52 52
 					<td><?= $item['user_rating'] ?> / 10 </td>
53
-					<td><?= $item['anime']['type'] ?></td>
53
+					<td><?= $item['anime']['show_type'] ?></td>
54 54
 					<td id="<?= $item['anime']['slug'] ?>">
55 55
 						Episodes: <br />
56 56
 						<span class="completed_number"><?= $item['episodes']['watched'] ?></span>&nbsp;/&nbsp;<span class="total_number"><?= $item['episodes']['total'] ?></span>
@@ -83,8 +83,8 @@
83 83
 						<p><?= $escape->html($item['notes']) ?></p>
84 84
 					</td>
85 85
 					<td class="align_left">
86
-						<?php sort($item['anime']['genres']) ?>
87
-						<?= implode(', ', $item['anime']['genres']) ?>
86
+						<?php sort($item['anime']->genres) ?>
87
+						<?= implode(', ', $item['anime']->genres) ?>
88 88
 					</td>
89 89
 				</tr>
90 90
 				<?php endforeach ?>

+ 1
- 0
composer.json View File

@@ -39,6 +39,7 @@
39 39
 	"phpmd/phpmd": "^2.4",
40 40
 	"phpstan/phpstan": "^0.9.1",
41 41
 	"phpunit/phpunit": "^6.0",
42
+	"roave/security-advisories": "dev-master",
42 43
 	"robmorgan/phinx": "^0.9.1",
43 44
 	"sebastian/phpcpd": "^3.0",
44 45
 	"spatie/phpunit-snapshot-assertions": "^1.2.0",

+ 1
- 1
src/API/Enum/AnimeWatchingStatus/Kitsu.php View File

@@ -21,7 +21,7 @@ use Aviat\Ion\Enum;
21 21
 /**
22 22
  * Possible values for watching status for the current anime
23 23
  */
24
-class Kitsu extends Enum {
24
+final class Kitsu extends Enum {
25 25
 	const WATCHING = 'current';
26 26
 	const PLAN_TO_WATCH = 'planned';
27 27
 	const ON_HOLD = 'on_hold';

+ 1
- 1
src/API/Enum/AnimeWatchingStatus/MAL.php View File

@@ -21,7 +21,7 @@ use Aviat\Ion\Enum;
21 21
 /**
22 22
  * Possible values for watching status for the current anime
23 23
  */
24
-class MAL extends Enum {
24
+final class MAL extends Enum {
25 25
 	const WATCHING = 1;
26 26
 	const COMPLETED = 2;
27 27
 	const ON_HOLD = 3;

+ 1
- 1
src/API/Enum/AnimeWatchingStatus/Route.php View File

@@ -21,7 +21,7 @@ use Aviat\Ion\Enum as Enum;
21 21
 /**
22 22
  * Possible values for current watching status of anime
23 23
  */
24
-class Route extends Enum {
24
+final class Route extends Enum {
25 25
 	const ALL = 'all';
26 26
 	const WATCHING = 'watching';
27 27
 	const PLAN_TO_WATCH = 'plan_to_watch';

+ 1
- 1
src/API/Enum/AnimeWatchingStatus/Title.php View File

@@ -21,7 +21,7 @@ use Aviat\Ion\Enum as Enum;
21 21
 /**
22 22
  * Possible values for current watching status of anime
23 23
  */
24
-class Title extends Enum {
24
+final class Title extends Enum {
25 25
 	const ALL = 'All';
26 26
 	const WATCHING = 'Currently Watching';
27 27
 	const PLAN_TO_WATCH = 'Plan to Watch';

+ 1
- 1
src/API/Enum/MangaReadingStatus/Kitsu.php View File

@@ -21,7 +21,7 @@ use Aviat\Ion\Enum;
21 21
 /**
22 22
  * Possible values for current reading status of manga
23 23
  */
24
-class Kitsu extends Enum {
24
+final class Kitsu extends Enum {
25 25
 	const READING = 'current';
26 26
 	const PLAN_TO_READ = 'planned';
27 27
 	const DROPPED = 'dropped';

+ 1
- 1
src/API/Enum/MangaReadingStatus/MAL.php View File

@@ -21,7 +21,7 @@ use Aviat\Ion\Enum;
21 21
 /**
22 22
  * Possible values for watching status for the current anime
23 23
  */
24
-class MAL extends Enum {
24
+final class MAL extends Enum {
25 25
 	const READING = 'reading';
26 26
 	const COMPLETED = 'completed';
27 27
 	const ON_HOLD = 'onhold';

+ 2
- 2
src/API/Enum/MangaReadingStatus/Route.php View File

@@ -16,12 +16,12 @@
16 16
 
17 17
 namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
18 18
 
19
-use Aviat\Ion\Enum as Enum;
19
+use Aviat\Ion\Enum;
20 20
 
21 21
 /**
22 22
  * Possible values for current reading status of manga
23 23
  */
24
-class Route extends Enum {
24
+final class Route extends Enum {
25 25
 	const ALL = 'all';
26 26
 	const READING = 'reading';
27 27
 	const PLAN_TO_READ = 'plan_to_read';

+ 2
- 2
src/API/Enum/MangaReadingStatus/Title.php View File

@@ -16,12 +16,12 @@
16 16
 
17 17
 namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus;
18 18
 
19
-use Aviat\Ion\Enum as Enum;
19
+use Aviat\Ion\Enum;
20 20
 
21 21
 /**
22 22
  * Possible values for current reading status of manga
23 23
  */
24
-class Title extends Enum {
24
+final class Title extends Enum {
25 25
 	const ALL = 'All';
26 26
 	const READING = 'Currently Reading';
27 27
 	const PLAN_TO_READ = 'Plan to Read';

+ 1
- 1
src/API/JsonAPI.php View File

@@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\API;
19 19
 /**
20 20
  * Class encapsulating Json API data structure for a request or response
21 21
  */
22
-class JsonAPI {
22
+final class JsonAPI {
23 23
 
24 24
 	/**
25 25
 	 * The full data array

+ 1
- 1
src/API/Kitsu.php View File

@@ -22,7 +22,7 @@ use DateTimeImmutable;
22 22
 /**
23 23
  * Data massaging helpers for the Kitsu API
24 24
  */
25
-class Kitsu {
25
+final class Kitsu {
26 26
 	const AUTH_URL = 'https://kitsu.io/api/oauth/token';
27 27
 	const AUTH_USER_ID_KEY = 'kitsu-auth-userid';
28 28
 	const AUTH_TOKEN_CACHE_KEY = 'kitsu-auth-token';

+ 3
- 3
src/API/Kitsu/Auth.php View File

@@ -28,7 +28,7 @@ use Exception;
28 28
 /**
29 29
  * Kitsu API Authentication
30 30
  */
31
-class Auth {
31
+final class Auth {
32 32
 	use CacheTrait;
33 33
 	use ContainerAware;
34 34
 
@@ -37,14 +37,14 @@ class Auth {
37 37
 	 *
38 38
 	 * @var Model
39 39
 	 */
40
-	protected $model;
40
+	private $model;
41 41
 
42 42
 	/**
43 43
 	 * Session object
44 44
 	 *
45 45
 	 * @var \Aura\Session\Segment
46 46
 	 */
47
-	protected $segment;
47
+	private $segment;
48 48
 
49 49
 	/**
50 50
 	 * Constructor

+ 1
- 1
src/API/Kitsu/Enum/AnimeAiringStatus.php View File

@@ -21,7 +21,7 @@ use Aviat\Ion\Enum as BaseEnum;
21 21
 /**
22 22
  * Status of when anime is being/was/will be aired
23 23
  */
24
-class AnimeAiringStatus extends BaseEnum {
24
+final class AnimeAiringStatus extends BaseEnum {
25 25
 	const NOT_YET_AIRED = 'Not Yet Aired';
26 26
 	const AIRING = 'Currently Airing';
27 27
 	const FINISHED_AIRING = 'Finished Airing';

+ 1
- 1
src/API/Kitsu/KitsuRequestBuilder.php View File

@@ -18,7 +18,7 @@ namespace Aviat\AnimeClient\API\Kitsu;
18 18
 
19 19
 use Aviat\AnimeClient\API\APIRequestBuilder;
20 20
 
21
-class KitsuRequestBuilder extends APIRequestBuilder {
21
+final class KitsuRequestBuilder extends APIRequestBuilder {
22 22
 
23 23
 	/**
24 24
 	 * The base url for api requests

+ 24
- 25
src/API/Kitsu/ListItem.php View File

@@ -25,39 +25,17 @@ use Aviat\AnimeClient\API\{
25 25
 	HummingbirdClient,
26 26
 	ListItemInterface
27 27
 };
28
+use Aviat\AnimeClient\Types\AbstractType;
28 29
 use Aviat\Ion\Di\ContainerAware;
29 30
 use Aviat\Ion\Json;
30 31
 
31 32
 /**
32 33
  * CRUD operations for Kitsu list items
33 34
  */
34
-class ListItem implements ListItemInterface {
35
+final class ListItem implements ListItemInterface {
35 36
 	use ContainerAware;
36 37
 	use KitsuTrait;
37 38
 
38
-	private function getAuthHeader()
39
-	{
40
-		$cache = $this->getContainer()->get('cache');
41
-		$cacheItem = $cache->getItem('kitsu-auth-token');
42
-		$sessionSegment = $this->getContainer()
43
-			->get('session')
44
-			->getSegment(SESSION_SEGMENT);
45
-
46
-		if ($sessionSegment->get('auth_token') !== NULL)
47
-		{
48
-			$token = $sessionSegment->get('auth_token');
49
-			return "bearer {$token}";
50
-		}
51
-
52
-		if ($cacheItem->isHit())
53
-		{
54
-			$token = $cacheItem->get();
55
-			return "bearer {$token}";
56
-		}
57
-
58
-		return FALSE;
59
-	}
60
-
61 39
 	public function create(array $data): Request
62 40
 	{
63 41
 		$body = [
@@ -134,7 +112,7 @@ class ListItem implements ListItemInterface {
134 112
 		return Json::decode(wait($response->getBody()));
135 113
 	}
136 114
 
137
-	public function update(string $id, array $data): Request
115
+	public function update(string $id, AbstractType $data): Request
138 116
 	{
139 117
 		$authHeader = $this->getAuthHeader();
140 118
 		$requestData = [
@@ -155,4 +133,25 @@ class ListItem implements ListItemInterface {
155 133
 
156 134
 		return $request->getFullRequest();
157 135
 	}
136
+
137
+	private function getAuthHeader()
138
+	{
139
+		$cache = $this->getContainer()->get('cache');
140
+		$cacheItem = $cache->getItem('kitsu-auth-token');
141
+		$sessionSegment = $this->getContainer()
142
+			->get('session')
143
+			->getSegment(SESSION_SEGMENT);
144
+
145
+		if ($sessionSegment->get('auth_token') !== NULL) {
146
+			$token = $sessionSegment->get('auth_token');
147
+			return "bearer {$token}";
148
+		}
149
+
150
+		if ($cacheItem->isHit()) {
151
+			$token = $cacheItem->get();
152
+			return "bearer {$token}";
153
+		}
154
+
155
+		return FALSE;
156
+	}
158 157
 }

+ 21
- 16
src/API/Kitsu/Model.php View File

@@ -36,17 +36,22 @@ use Aviat\AnimeClient\API\Kitsu\Transformer\{
36 36
 	MangaTransformer,
37 37
 	MangaListTransformer
38 38
 };
39
+use Aviat\AnimeClient\Types\{
40
+	Anime,
41
+	AnimeFormItem,
42
+	AnimeListItem
43
+};
39 44
 use Aviat\Ion\{Di\ContainerAware, Json};
40 45
 
41 46
 /**
42 47
  * Kitsu API Model
43 48
  */
44
-class Model {
49
+final class Model {
45 50
 	use CacheTrait;
46 51
 	use ContainerAware;
47 52
 	use KitsuTrait;
48 53
 
49
-	protected const LIST_PAGE_SIZE = 100;
54
+	private const LIST_PAGE_SIZE = 100;
50 55
 
51 56
 	/**
52 57
 	 * Class to map anime list items
@@ -55,27 +60,27 @@ class Model {
55 60
 	 *
56 61
 	 * @var AnimeListTransformer
57 62
 	 */
58
-	protected $animeListTransformer;
63
+	private $animeListTransformer;
59 64
 
60 65
 	/**
61 66
 	 * @var AnimeTransformer
62 67
 	 */
63
-	protected $animeTransformer;
68
+	private $animeTransformer;
64 69
 
65 70
 	/**
66 71
 	 * @var ListItem
67 72
 	 */
68
-	protected $listItem;
73
+	private $listItem;
69 74
 
70 75
 	/**
71 76
 	 * @var MangaTransformer
72 77
 	 */
73
-	protected $mangaTransformer;
78
+	private $mangaTransformer;
74 79
 
75 80
 	/**
76 81
 	 * @var MangaListTransformer
77 82
 	 */
78
-	protected $mangaListTransformer;
83
+	private $mangaListTransformer;
79 84
 
80 85
 	/**
81 86
 	 * Constructor
@@ -313,15 +318,15 @@ class Model {
313 318
 	 * Get information about a particular anime
314 319
 	 *
315 320
 	 * @param string $slug
316
-	 * @return array
321
+	 * @return Anime
317 322
 	 */
318
-	public function getAnime(string $slug): array
323
+	public function getAnime(string $slug): Anime
319 324
 	{
320 325
 		$baseData = $this->getRawMediaData('anime', $slug);
321 326
 
322 327
 		if (empty($baseData))
323 328
 		{
324
-			return [];
329
+			return new Anime();
325 330
 		}
326 331
 
327 332
 		$transformed = $this->animeTransformer->transform($baseData);
@@ -803,9 +808,9 @@ class Model {
803 808
 	 * Get the data for a specific list item, generally for editing
804 809
 	 *
805 810
 	 * @param string $listId - The unique identifier of that list item
806
-	 * @return array
811
+	 * @return mixed
807 812
 	 */
808
-	public function getListItem(string $listId): array
813
+	public function getListItem(string $listId)
809 814
 	{
810 815
 		$baseData = $this->listItem->get($listId);
811 816
 		$included = JsonAPI::organizeIncludes($baseData['included']);
@@ -813,12 +818,12 @@ class Model {
813 818
 
814 819
 		switch (TRUE)
815 820
 		{
816
-			case in_array('anime', array_keys($included)):
821
+			case array_key_exists('anime', $included): // in_array('anime', array_keys($included)):
817 822
 				$included = JsonAPI::inlineIncludedRelationships($included, 'anime');
818 823
 				$baseData['data']['included'] = $included;
819 824
 				return $this->animeListTransformer->transform($baseData['data']);
820 825
 
821
-			case in_array('manga', array_keys($included)):
826
+			case array_key_exists('manga', $included): // in_array('manga', array_keys($included)):
822 827
 				$included = JsonAPI::inlineIncludedRelationships($included, 'manga');
823 828
 				$baseData['data']['included'] = $included;
824 829
 				$baseData['data']['manga'] = $baseData['included'][0];
@@ -832,10 +837,10 @@ class Model {
832 837
 	/**
833 838
 	 * Modify a list item
834 839
 	 *
835
-	 * @param array $data
840
+	 * @param AnimeFormItem $data
836 841
 	 * @return Request
837 842
 	 */
838
-	public function updateListItem(array $data): Request
843
+	public function updateListItem(AnimeFormItem $data): Request
839 844
 	{
840 845
 		return $this->listItem->update($data['id'], $data['data']);
841 846
 	}

+ 26
- 17
src/API/Kitsu/Transformer/AnimeListTransformer.php View File

@@ -17,21 +17,27 @@
17 17
 namespace Aviat\AnimeClient\API\Kitsu\Transformer;
18 18
 
19 19
 use Aviat\AnimeClient\API\Kitsu;
20
+use Aviat\AnimeClient\Types\{
21
+	Anime,
22
+	AnimeFormItem,
23
+	AnimeFormItemData,
24
+	AnimeListItem
25
+};
20 26
 use Aviat\Ion\Transformer\AbstractTransformer;
21 27
 
22 28
 /**
23 29
  * Transformer for anime list
24 30
  */
25
-class AnimeListTransformer extends AbstractTransformer {
31
+final class AnimeListTransformer extends AbstractTransformer {
26 32
 
27 33
 	/**
28 34
 	 * Convert raw api response to a more
29 35
 	 * logical and workable structure
30 36
 	 *
31 37
 	 * @param  array  $item API library item
32
-	 * @return array
38
+	 * @return AnimeListItem
33 39
 	 */
34
-	public function transform($item): array
40
+	public function transform($item): AnimeListItem
35 41
 	{
36 42
 		$included = $item['included'];
37 43
 		$animeId = $item['relationships']['media']['data']['id'];
@@ -66,7 +72,10 @@ class AnimeListTransformer extends AbstractTransformer {
66 72
 			? Kitsu::parseListItemStreamingLinks($included, $animeId)
67 73
 			: [];
68 74
 
69
-		return [
75
+		$titles = Kitsu::filterTitles($anime);
76
+		$title = array_shift($titles);
77
+
78
+		return new AnimeListItem([
70 79
 			'id' => $item['id'],
71 80
 			'mal_id' => $MALid,
72 81
 			'episodes' => [
@@ -81,24 +90,24 @@ class AnimeListTransformer extends AbstractTransformer {
81 90
 				'started' => $anime['startDate'],
82 91
 				'ended' => $anime['endDate']
83 92
 			],
84
-			'anime' => [
93
+			'anime' => new Anime([
85 94
 				'id' => $animeId,
86 95
 				'age_rating' => $anime['ageRating'],
87
-				'title' => $anime['canonicalTitle'],
88
-				'titles' => Kitsu::filterTitles($anime),
96
+				'title' => $title,
97
+				'titles' => $titles,
89 98
 				'slug' => $anime['slug'],
90
-				'type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(),
91
-				'image' => $anime['posterImage']['small'],
99
+				'show_type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(),
100
+				'cover_image' => $anime['posterImage']['small'],
92 101
 				'genres' => $genres,
93 102
 				'streaming_links' => $streamingLinks,
94
-			],
103
+			]),
95 104
 			'watching_status' => $item['attributes']['status'],
96 105
 			'notes' => $item['attributes']['notes'],
97 106
 			'rewatching' => (bool) $item['attributes']['reconsuming'],
98 107
 			'rewatched' => (int) $item['attributes']['reconsumeCount'],
99 108
 			'user_rating' => $rating,
100 109
 			'private' => $item['attributes']['private'] ?? FALSE,
101
-		];
110
+		]);
102 111
 	}
103 112
 
104 113
 	/**
@@ -106,24 +115,24 @@ class AnimeListTransformer extends AbstractTransformer {
106 115
 	 * api response format
107 116
 	 *
108 117
 	 * @param array $item Transformed library item
109
-	 * @return array API library item
118
+	 * @return AnimeFormItem API library item
110 119
 	 */
111
-	public function untransform($item): array
120
+	public function untransform($item): AnimeFormItem
112 121
 	{
113 122
 		$privacy = (array_key_exists('private', $item) && $item['private']);
114 123
 		$rewatching = (array_key_exists('rewatching', $item) && $item['rewatching']);
115 124
 
116
-		$untransformed = [
125
+		$untransformed = new AnimeFormItem([
117 126
 			'id' => $item['id'],
118 127
 			'mal_id' => $item['mal_id'] ?? NULL,
119
-			'data' => [
128
+			'data' => new AnimeFormItemData([
120 129
 				'status' => $item['watching_status'],
121 130
 				'reconsuming' => $rewatching,
122 131
 				'reconsumeCount' => $item['rewatched'],
123 132
 				'notes' => $item['notes'],
124 133
 				'private' => $privacy
125
-			]
126
-		];
134
+			])
135
+		]);
127 136
 
128 137
 		if (is_numeric($item['episodes_watched']) && $item['episodes_watched'] > 0)
129 138
 		{

+ 8
- 7
src/API/Kitsu/Transformer/AnimeTransformer.php View File

@@ -17,31 +17,32 @@
17 17
 namespace Aviat\AnimeClient\API\Kitsu\Transformer;
18 18
 
19 19
 use Aviat\AnimeClient\API\{JsonAPI, Kitsu};
20
+use Aviat\AnimeClient\Types\Anime;
20 21
 use Aviat\Ion\Transformer\AbstractTransformer;
21 22
 
22 23
 /**
23 24
  * Transformer for anime description page
24 25
  */
25
-class AnimeTransformer extends AbstractTransformer {
26
+final class AnimeTransformer extends AbstractTransformer {
26 27
 
27 28
 	/**
28 29
 	 * Convert raw api response to a more
29 30
 	 * logical and workable structure
30 31
 	 *
31 32
 	 * @param  array  $item API library item
32
-	 * @return array
33
+	 * @return Anime
33 34
 	 */
34
-	public function transform($item): array
35
+	public function transform($item): Anime
35 36
 	{
36
-
37 37
 		$item['included'] = JsonAPI::organizeIncludes($item['included']);
38 38
 		$genres = $item['included']['categories'] ?? [];
39 39
 		$item['genres'] = array_column($genres, 'title') ?? [];
40 40
 		sort($item['genres']);
41 41
 
42 42
 		$titles = Kitsu::filterTitles($item);
43
+		$title = array_shift($titles);
43 44
 
44
-		return [
45
+		return new Anime([
45 46
 			'age_rating' => $item['ageRating'],
46 47
 			'age_rating_guide' => $item['ageRatingGuide'],
47 48
 			'cover_image' => $item['posterImage']['small'],
@@ -54,10 +55,10 @@ class AnimeTransformer extends AbstractTransformer {
54 55
 			'status' => Kitsu::getAiringStatus($item['startDate'], $item['endDate']),
55 56
 			'streaming_links' => Kitsu::parseStreamingLinks($item['included']),
56 57
 			'synopsis' => $item['synopsis'],
57
-			'title' => $titles[0],
58
+			'title' => $title,
58 59
 			'titles' => $titles,
59 60
 			'trailer_id' => $item['youtubeVideoId'],
60 61
 			'url' => "https://kitsu.io/anime/{$item['slug']}",
61
-		];
62
+		]);
62 63
 	}
63 64
 }

+ 1
- 1
src/API/Kitsu/Transformer/MangaListTransformer.php View File

@@ -23,7 +23,7 @@ use Aviat\Ion\Transformer\AbstractTransformer;
23 23
 /**
24 24
  * Data transformation class for zippered Hummingbird manga
25 25
  */
26
-class MangaListTransformer extends AbstractTransformer {
26
+final class MangaListTransformer extends AbstractTransformer {
27 27
 
28 28
 	use StringWrapper;
29 29
 

+ 1
- 1
src/API/Kitsu/Transformer/MangaTransformer.php View File

@@ -21,7 +21,7 @@ use Aviat\Ion\Transformer\AbstractTransformer;
21 21
 /**
22 22
  * Transformer for anime description page
23 23
  */
24
-class MangaTransformer extends AbstractTransformer {
24
+final class MangaTransformer extends AbstractTransformer {
25 25
 
26 26
 	/**
27 27
 	 * Convert raw api response to a more

+ 3
- 2
src/API/ListItemInterface.php View File

@@ -17,6 +17,7 @@
17 17
 namespace Aviat\AnimeClient\API;
18 18
 
19 19
 use Amp\Artax\Request;
20
+use Aviat\AnimeClient\Types\AbstractType;
20 21
 
21 22
 /**
22 23
  * Common interface for anime and manga list item CRUD
@@ -43,10 +44,10 @@ interface ListItemInterface {
43 44
 	 * Update a list item
44 45
 	 *
45 46
 	 * @param string $id - The id of the list item to update
46
-	 * @param array $data - The data with which to update the list item
47
+	 * @param AbstractType $data - The data with which to update the list item
47 48
 	 * @return Request
48 49
 	 */
49
-	public function update(string $id, array $data): Request;
50
+	public function update(string $id, AbstractType $data): Request;
50 51
 
51 52
 	/**
52 53
 	 * Delete a list item

+ 1
- 1
src/API/MAL.php View File

@@ -28,7 +28,7 @@ use Aviat\AnimeClient\API\Enum\{
28 28
 /**
29 29
  * Constants and mappings for the My Anime List API
30 30
  */
31
-class MAL {
31
+final class MAL {
32 32
 	const AUTH_URL = 'https://myanimelist.net/api/account/verify_credentials.xml';
33 33
 	const BASE_URL = 'https://myanimelist.net/api/';
34 34
 

+ 4
- 3
src/API/MAL/ListItem.php View File

@@ -20,12 +20,13 @@ use Amp\Artax\{FormBody, Request};
20 20
 use Aviat\AnimeClient\API\{
21 21
 	XML
22 22
 };
23
+use Aviat\AnimeClient\Types\AbstractType;
23 24
 use Aviat\Ion\Di\ContainerAware;
24 25
 
25 26
 /**
26 27
  * CRUD operations for MAL list items
27 28
  */
28
-class ListItem {
29
+final class ListItem {
29 30
 	use ContainerAware;
30 31
 	use MALTrait;
31 32
 
@@ -84,11 +85,11 @@ class ListItem {
84 85
 	 * Update a list item
85 86
 	 *
86 87
 	 * @param string $id
87
-	 * @param array $data
88
+	 * @param AbstractType $data
88 89
 	 * @param string $type
89 90
 	 * @return Request
90 91
 	 */
91
-	public function update(string $id, array $data, string $type = 'anime'): Request
92
+	public function update(string $id, AbstractType $data, string $type = 'anime'): Request
92 93
 	{
93 94
 		$config = $this->container->get('config');
94 95
 

+ 1
- 1
src/API/MAL/MALRequestBuilder.php View File

@@ -21,7 +21,7 @@ use Aviat\AnimeClient\API\{
21 21
 	MAL as M
22 22
 };
23 23
 
24
-class MALRequestBuilder extends APIRequestBuilder {
24
+final class MALRequestBuilder extends APIRequestBuilder {
25 25
 
26 26
 	/**
27 27
 	 * The base url for api requests

+ 4
- 3
src/API/MAL/Model.php View File

@@ -24,12 +24,13 @@ use Aviat\AnimeClient\API\MAL\{
24 24
 };
25 25
 use Aviat\AnimeClient\API\XML;
26 26
 use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
27
+use Aviat\AnimeClient\Types\{Anime, AnimeFormItem};
27 28
 use Aviat\Ion\Di\ContainerAware;
28 29
 
29 30
 /**
30 31
  * MyAnimeList API Model
31 32
  */
32
-class Model {
33
+final class Model {
33 34
 	use ContainerAware;
34 35
 	use MALTrait;
35 36
 
@@ -147,11 +148,11 @@ class Model {
147 148
 	/**
148 149
 	 * Update a list item
149 150
 	 *
150
-	 * @param array $data
151
+	 * @param AnimeFormItem $data
151 152
 	 * @param string $type "anime" or "manga"
152 153
 	 * @return Request
153 154
 	 */
154
-	public function updateListItem(array $data, string $type = 'anime'): Request
155
+	public function updateListItem(AnimeFormItem $data, string $type = 'anime'): Request
155 156
 	{
156 157
 		$updateData = [];
157 158
 

+ 8
- 9
src/API/MAL/Transformer/AnimeListTransformer.php View File

@@ -17,12 +17,13 @@
17 17
 namespace Aviat\AnimeClient\API\MAL\Transformer;
18 18
 
19 19
 use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
20
+use Aviat\AnimeClient\Types\{AnimeFormItem, AnimeFormItemData};
20 21
 use Aviat\Ion\Transformer\AbstractTransformer;
21 22
 
22 23
 /**
23 24
  * Transformer for updating MAL List
24 25
  */
25
-class AnimeListTransformer extends AbstractTransformer {
26
+final class AnimeListTransformer extends AbstractTransformer {
26 27
 	/**
27 28
 	 * Identity transformation
28 29
 	 *
@@ -38,16 +39,14 @@ class AnimeListTransformer extends AbstractTransformer {
38 39
 	 * Transform Kitsu episode data to MAL episode data
39 40
 	 *
40 41
 	 * @param array $item
41
-	 * @return array
42
+	 * @return AnimeFormItem
42 43
 	 */
43
-	public function untransform(array $item): array
44
+	public function untransform(array $item): AnimeFormItem
44 45
 	{
45
-		$map = [
46
+		$map = new AnimeFormItem([
46 47
 			'id' => $item['mal_id'],
47
-			'data' => []
48
-		];
49
-
50
-		$data =& $item['data'];
48
+			'data' => new AnimeFormItemData([]),
49
+		]);
51 50
 
52 51
 		foreach($item['data'] as $key => $value)
53 52
 		{
@@ -56,7 +55,7 @@ class AnimeListTransformer extends AbstractTransformer {
56 55
 				case 'progress':
57 56
 					$map['data']['episode'] = $value;
58 57
 				break;
59
-				
58
+
60 59
 				case 'notes':
61 60
 					$map['data']['comments'] = $value;
62 61
 				break;

+ 1
- 1
src/API/MAL/Transformer/MangaListTransformer.php View File

@@ -22,7 +22,7 @@ use Aviat\Ion\Transformer\AbstractTransformer;
22 22
 /**
23 23
  * Transformer for updating MAL List
24 24
  */
25
-class MangaListTransformer extends AbstractTransformer {
25
+final class MangaListTransformer extends AbstractTransformer {
26 26
 	/**
27 27
 	 * Identity transformation
28 28
 	 *

+ 1
- 1
src/API/Mapping/AnimeWatchingStatus.php View File

@@ -23,7 +23,7 @@ use Aviat\Ion\Enum;
23 23
  * Anime watching status mappings, among Kitsu, MAL, Page titles
24 24
  * and url route segments
25 25
  */
26
-class AnimeWatchingStatus extends Enum {
26
+final class AnimeWatchingStatus extends Enum {
27 27
 	const KITSU_TO_MAL = [
28 28
 		Kitsu::WATCHING => MAL::WATCHING,
29 29
 		Kitsu::PLAN_TO_WATCH => MAL::PLAN_TO_WATCH,

+ 1
- 1
src/API/Mapping/MangaReadingStatus.php View File

@@ -23,7 +23,7 @@ use Aviat\Ion\Enum;
23 23
  * Manga reading status mappings, among Kitsu, MAL, Page titles
24 24
  * and url route segments
25 25
  */
26
-class MangaReadingStatus extends Enum {
26
+final class MangaReadingStatus extends Enum {
27 27
 	const KITSU_TO_MAL = [
28 28
 		Kitsu::READING => MAL::READING,
29 29
 		Kitsu::PLAN_TO_READ => MAL::PLAN_TO_READ,

+ 3
- 5
src/API/ParallelAPIRequest.php View File

@@ -22,14 +22,14 @@ use function Amp\Promise\{all, wait};
22 22
 /**
23 23
  * Class to simplify making and validating simultaneous requests
24 24
  */
25
-class ParallelAPIRequest {
25
+final class ParallelAPIRequest {
26 26
 
27 27
 	/**
28 28
 	 * Set of requests to make in parallel
29 29
 	 *
30 30
 	 * @var array
31 31
 	 */
32
-	protected $requests = [];
32
+	private $requests = [];
33 33
 
34 34
 	/**
35 35
 	 * Add a request
@@ -76,9 +76,7 @@ class ParallelAPIRequest {
76 76
 		{
77 77
 			$promises[$key] = call(function () use ($client, $url) {
78 78
 				$response = yield $client->request($url);
79
-				$body = yield $response->getBody();
80
-
81
-				return $body;
79
+				return yield $response->getBody();
82 80
 			});
83 81
 		}
84 82
 

+ 1
- 1
src/API/XML.php View File

@@ -21,7 +21,7 @@ use DOMDocument, DOMNode, DOMNodeList, InvalidArgumentException;
21 21
 /**
22 22
  * XML <=> PHP Array codec
23 23
  */
24
-class XML {
24
+final class XML {
25 25
 
26 26
 	/**
27 27
 	 * XML representation of the data

+ 1
- 1
src/Command/CacheClear.php View File

@@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\Command;
19 19
 /**
20 20
  * Clears the API Cache
21 21
  */
22
-class CacheClear extends BaseCommand {
22
+final class CacheClear extends BaseCommand {
23 23
 	/**
24 24
 	 * Clear the API cache
25 25
 	 *

+ 1
- 1
src/Command/CachePrime.php View File

@@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\Command;
19 19
 /**
20 20
  * Clears the API Cache
21 21
  */
22
-class CachePrime extends BaseCommand {
22
+final class CachePrime extends BaseCommand {
23 23
 	/**
24 24
 	 * Clear, then prime the API cache
25 25
 	 *

+ 1
- 1
src/Command/SyncLists.php View File

@@ -32,7 +32,7 @@ use DateTime;
32 32
 /**
33 33
  * Clears the API Cache
34 34
  */
35
-class SyncLists extends BaseCommand {
35
+final class SyncLists extends BaseCommand {
36 36
 
37 37
 	/**
38 38
 	 * Model for making requests to Kitsu API

+ 3
- 3
src/Controller/Anime.php View File

@@ -27,7 +27,7 @@ use Aviat\Ion\StringWrapper;
27 27
 /**
28 28
  * Controller for Anime-related pages
29 29
  */
30
-class Anime extends BaseController {
30
+final class Anime extends BaseController {
31 31
 
32 32
 	use StringWrapper;
33 33
 
@@ -277,7 +277,7 @@ class Anime extends BaseController {
277 277
 		$show_data = $this->model->getAnime($animeId);
278 278
 		$characters = [];
279 279
 
280
-		if (empty($show_data))
280
+		if ($show_data->title === '')
281 281
 		{
282 282
 			$this->notFound(
283 283
 				$this->config->get('whose_list') .
@@ -301,7 +301,7 @@ class Anime extends BaseController {
301 301
 			'title' => $this->formatTitle(
302 302
 				$this->config->get('whose_list') . "'s Anime List",
303 303
 				'Anime',
304
-				$show_data['titles'][0]
304
+				$show_data->title
305 305
 			),
306 306
 			'characters' => $characters,
307 307
 			'show_data' => $show_data,

+ 1
- 1
src/Controller/AnimeCollection.php View File

@@ -26,7 +26,7 @@ use Aviat\Ion\Di\ContainerInterface;
26 26
 /**
27 27
  * Controller for Anime collection pages
28 28
  */
29
-class AnimeCollection extends BaseController {
29
+final class AnimeCollection extends BaseController {
30 30
 
31 31
 	/**
32 32
 	 * The anime collection model

+ 1
- 1
src/Controller/Character.php View File

@@ -23,7 +23,7 @@ use Aviat\Ion\ArrayWrapper;
23 23
 /**
24 24
  * Controller for character description pages
25 25
  */
26
-class Character extends BaseController {
26
+final class Character extends BaseController {
27 27
 
28 28
 	use ArrayWrapper;
29 29
 

+ 1
- 1
src/Controller/Index.php View File

@@ -25,7 +25,7 @@ use Aviat\Ion\View\HtmlView;
25 25
 /**
26 26
  * Controller for handling routes that don't fit elsewhere
27 27
  */
28
-class Index extends BaseController {
28
+final class Index extends BaseController {
29 29
 
30 30
 	/**
31 31
 	 * Purges the API cache

+ 1
- 1
src/Controller/Manga.php View File

@@ -26,7 +26,7 @@ use Aviat\Ion\{Json, StringWrapper};
26 26
 /**
27 27
  * Controller for manga list
28 28
  */
29
-class Manga extends Controller {
29
+final class Manga extends Controller {
30 30
 
31 31
 	use StringWrapper;
32 32
 

+ 1
- 1
src/Controller/MangaCollection.php View File

@@ -26,7 +26,7 @@ use Aviat\Ion\Di\ContainerInterface;
26 26
 /**
27 27
  * Controller for manga collection pages
28 28
  */
29
-class MangaCollection extends BaseController {
29
+final class MangaCollection extends BaseController {
30 30
 
31 31
 	/**
32 32
 	 * The manga collection model

+ 1
- 1
src/Dispatcher.php View File

@@ -28,7 +28,7 @@ use Aviat\Ion\StringWrapper;
28 28
 /**
29 29
  * Basic routing/ dispatch
30 30
  */
31
-class Dispatcher extends RoutingBase {
31
+final class Dispatcher extends RoutingBase {
32 32
 
33 33
 	use StringWrapper;
34 34
 

+ 3
- 2
src/Helper/Menu.php View File

@@ -17,13 +17,14 @@
17 17
 namespace Aviat\AnimeClient\Helper;
18 18
 
19 19
 use Aviat\AnimeClient\MenuGenerator;
20
+use Aviat\Ion\Di\ContainerAware;
20 21
 
21 22
 /**
22 23
  * MenuGenerator helper wrapper
23 24
  */
24
-class Menu {
25
+final class Menu {
25 26
 
26
-	use \Aviat\Ion\Di\ContainerAware;
27
+	use ContainerAware;
27 28
 
28 29
 	/**
29 30
 	 * Create the html for the selected menu

+ 1
- 1
src/MenuGenerator.php View File

@@ -25,7 +25,7 @@ use Aviat\Ion\Exception\ConfigException;
25 25
 /**
26 26
  * Helper object to manage menu creation and selection
27 27
  */
28
-class MenuGenerator extends UrlGenerator {
28
+final class MenuGenerator extends UrlGenerator {
29 29
 
30 30
 	use ArrayWrapper;
31 31
 	use StringWrapper;

+ 1
- 1
src/Model/API.php View File

@@ -44,7 +44,7 @@ class API {
44 44
 
45 45
 		foreach ($array as $key => $item)
46 46
 		{
47
-			$sort[$key] = $item[$sortKey]['titles'][0];
47
+			$sort[$key] = $item[$sortKey]['title'];
48 48
 		}
49 49
 
50 50
 		array_multisort($sort, SORT_ASC, $array);

+ 12
- 7
src/Model/Anime.php View File

@@ -18,13 +18,18 @@ namespace Aviat\AnimeClient\Model;
18 18
 
19 19
 use Aviat\AnimeClient\API\ParallelAPIRequest;
20 20
 use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
21
+use Aviat\AnimeClient\Types\{
22
+	Anime as AnimeType,
23
+	AnimeFormItem,
24
+	AnimeListItem,
25
+};
21 26
 use Aviat\Ion\Di\ContainerInterface;
22 27
 use Aviat\Ion\Json;
23 28
 
24 29
 /**
25 30
  * Model for handling requests dealing with the anime list
26 31
  */
27
-class Anime extends API {
32
+final class Anime extends API {
28 33
 	/**
29 34
 	 * Model for making requests to Kitsu API
30 35
 	 *
@@ -93,9 +98,9 @@ class Anime extends API {
93 98
 	 * Get information about an anime from its slug
94 99
 	 *
95 100
 	 * @param string $slug
96
-	 * @return array
101
+	 * @return AnimeType
97 102
 	 */
98
-	public function getAnime(string $slug): array
103
+	public function getAnime(string $slug): AnimeType
99 104
 	{
100 105
 		return $this->kitsuModel->getAnime($slug);
101 106
 	}
@@ -127,9 +132,9 @@ class Anime extends API {
127 132
 	 * for editing/updating that item
128 133
 	 *
129 134
 	 * @param string $itemId
130
-	 * @return array
135
+	 * @return AnimeListItem
131 136
 	 */
132
-	public function getLibraryItem(string $itemId): array
137
+	public function getLibraryItem(string $itemId): AnimeListItem
133 138
 	{
134 139
 		return $this->kitsuModel->getListItem($itemId);
135 140
 	}
@@ -166,10 +171,10 @@ class Anime extends API {
166 171
 	/**
167 172
 	 * Update a list entry
168 173
 	 *
169
-	 * @param array $data
174
+	 * @param AnimeFormItem $data
170 175
 	 * @return array
171 176
 	 */
172
-	public function updateLibraryItem(array $data): array
177
+	public function updateLibraryItem(AnimeFormItem $data): array
173 178
 	{
174 179
 		$requester = new ParallelAPIRequest();
175 180
 

+ 1
- 1
src/Model/AnimeCollection.php View File

@@ -22,7 +22,7 @@ use PDO;
22 22
 /**
23 23
  * Model for getting anime collection data
24 24
  */
25
-class AnimeCollection extends Collection {
25
+final class AnimeCollection extends Collection {
26 26
 
27 27
 	/**
28 28
 	 * Anime API Model

+ 1
- 1
src/Model/Manga.php View File

@@ -27,7 +27,7 @@ use Aviat\Ion\Json;
27 27
 /**
28 28
  * Model for handling requests dealing with the manga list
29 29
  */
30
-class Manga extends API
30
+final class Manga extends API
31 31
 {
32 32
 	/**
33 33
 	 * Model for making requests to Kitsu API

+ 1
- 1
src/Model/MangaCollection.php View File

@@ -22,7 +22,7 @@ use PDO;
22 22
 /**
23 23
  * Model for getting anime collection data
24 24
  */
25
-class MangaCollection extends Collection {
25
+final class MangaCollection extends Collection {
26 26
 
27 27
 	/**
28 28
 	 * Manga API Model

+ 121
- 0
src/Types/AbstractType.php View File

@@ -0,0 +1,121 @@
1
+<?php declare(strict_types=1);
2
+/**
3
+ * Hummingbird Anime List Client
4
+ *
5
+ * An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
6
+ *
7
+ * PHP version 7
8
+ *
9
+ * @package     HummingbirdAnimeClient
10
+ * @author      Timothy J. Warren <tim@timshomepage.net>
11
+ * @copyright   2015 - 2018  Timothy J. Warren
12
+ * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
+ * @version     4.0
14
+ * @link        https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
15
+ */
16
+
17
+namespace Aviat\AnimeClient\Types;
18
+
19
+use ArrayAccess;
20
+use LogicException;
21
+
22
+abstract class AbstractType implements ArrayAccess {
23
+	/**
24
+	 * Sets the properties by using the constructor
25
+	 *
26
+	 * @param array $data
27
+	 */
28
+	public function __construct(array $data = [])
29
+	{
30
+		foreach ($data as $key => $value) {
31
+			$this->$key = $value;
32
+		}
33
+	}
34
+
35
+	/**
36
+	 * See if a property is set
37
+	 *
38
+	 * @param $name
39
+	 * @return bool
40
+	 */
41
+	public function __isset($name): bool
42
+	{
43
+		return property_exists($this, $name);
44
+	}
45
+
46
+	/**
47
+	 * Set a property on the type object
48
+	 *
49
+	 * @param string $name
50
+	 * @param mixed $value
51
+	 * @return void
52
+	 */
53
+	public function __set($name, $value): void
54
+	{
55
+		if (!property_exists($this, $name)) {
56
+			$existing = json_encode($this);
57
+
58
+			throw new LogicException("Trying to set non-existent property: '$name'. Existing properties: $existing");
59
+		}
60
+
61
+		$this->$name = $value;
62
+	}
63
+
64
+	/**
65
+	 * Get a property from the type object
66
+	 *
67
+	 * @param string $name
68
+	 * @return mixed
69
+	 */
70
+	public function __get($name)
71
+	{
72
+		if (property_exists($this, $name)) {
73
+			return $this->$name;
74
+		}
75
+
76
+		throw new LogicException("Trying to get non-existent property: '$name'");
77
+	}
78
+
79
+	/**
80
+	 * Implementing ArrayAccess
81
+	 *
82
+	 * @param $offset
83
+	 * @return bool
84
+	 */
85
+	public function offsetExists($offset): bool
86
+	{
87
+		return $this->__isset($offset);
88
+	}
89
+
90
+	/**
91
+	 * Implementing ArrayAccess
92
+	 *
93
+	 * @param $offset
94
+	 * @return mixed
95
+	 */
96
+	public function offsetGet($offset)
97
+	{
98
+		return $this->__get($offset);
99
+	}
100
+
101
+	/**
102
+	 * Implementing ArrayAccess
103
+	 *
104
+	 * @param $offset
105
+	 * @param $value
106
+	 */
107
+	public function offsetSet($offset, $value): void
108
+	{
109
+		$this->__set($offset, $value);
110
+	}
111
+
112
+	/**
113
+	 * Implementing ArrayAccess
114
+	 *
115
+	 * @param $offset
116
+	 */
117
+	public function offsetUnset($offset): void
118
+	{
119
+		// Do nothing!
120
+	}
121
+}

+ 40
- 0
src/Types/Anime.php View File

@@ -0,0 +1,40 @@
1
+<?php declare(strict_types=1);
2
+/**
3
+ * Hummingbird Anime List Client
4
+ *
5
+ * An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
6
+ *
7
+ * PHP version 7
8
+ *
9
+ * @package     HummingbirdAnimeClient
10
+ * @author      Timothy J. Warren <tim@timshomepage.net>
11
+ * @copyright   2015 - 2018  Timothy J. Warren
12
+ * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
+ * @version     4.0
14
+ * @link        https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
15
+ */
16
+
17
+namespace Aviat\AnimeClient\Types;
18
+
19
+/**
20
+ * Type representing an Anime object for display
21
+ */
22
+final class Anime extends AbstractType {
23
+	public $age_rating;
24
+	public $age_rating_guide;
25
+	public $cover_image;
26
+	public $episode_count;
27
+	public $episode_length;
28
+	public $genres;
29
+	public $id;
30
+	public $included;
31
+	public $show_type;
32
+	public $slug;
33
+	public $status;
34
+	public $streaming_links;
35
+	public $synopsis;
36
+	public $title;
37
+	public $titles;
38
+	public $trailer_id;
39
+	public $url;
40
+}

+ 26
- 0
src/Types/AnimeFormItem.php View File

@@ -0,0 +1,26 @@
1
+<?php declare(strict_types=1);
2
+/**
3
+ * Hummingbird Anime List Client
4
+ *
5
+ * An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
6
+ *
7
+ * PHP version 7
8
+ *
9
+ * @package     HummingbirdAnimeClient
10
+ * @author      Timothy J. Warren <tim@timshomepage.net>
11
+ * @copyright   2015 - 2018  Timothy J. Warren
12
+ * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
+ * @version     4.0
14
+ * @link        https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
15
+ */
16
+
17
+namespace Aviat\AnimeClient\Types;
18
+
19
+/**
20
+ * Type representing an Anime object for display
21
+ */
22
+final class AnimeFormItem extends AbstractType {
23
+	public $data;
24
+	public $id;
25
+	public $mal_id;
26
+}

+ 30
- 0
src/Types/AnimeFormItemData.php View File

@@ -0,0 +1,30 @@
1
+<?php declare(strict_types=1);
2
+/**
3
+ * Hummingbird Anime List Client
4
+ *
5
+ * An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
6
+ *
7
+ * PHP version 7
8
+ *
9
+ * @package     HummingbirdAnimeClient
10
+ * @author      Timothy J. Warren <tim@timshomepage.net>
11
+ * @copyright   2015 - 2018  Timothy J. Warren
12
+ * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
+ * @version     4.0
14
+ * @link        https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
15
+ */
16
+
17
+namespace Aviat\AnimeClient\Types;
18
+
19
+/**
20
+ * Type representing an Anime object for display
21
+ */
22
+final class AnimeFormItemData extends AbstractType {
23
+	public $notes;
24
+	public $private;
25
+	public $progress;
26
+	public $rating;
27
+	public $reconsumeCount;
28
+	public $reconsuming;
29
+	public $status;
30
+}

+ 42
- 0
src/Types/AnimeListItem.php View File

@@ -0,0 +1,42 @@
1
+<?php declare(strict_types=1);
2
+/**
3
+ * Hummingbird Anime List Client
4
+ *
5
+ * An API client for Kitsu and MyAnimeList to manage anime and manga watch lists
6
+ *
7
+ * PHP version 7
8
+ *
9
+ * @package     HummingbirdAnimeClient
10
+ * @author      Timothy J. Warren <tim@timshomepage.net>
11
+ * @copyright   2015 - 2018  Timothy J. Warren
12
+ * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
13
+ * @version     4.0
14
+ * @link        https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
15
+ */
16
+
17
+namespace Aviat\AnimeClient\Types;
18
+
19
+/**
20
+ * Type representing an Anime object for display
21
+ */
22
+final class AnimeListItem extends AbstractType {
23
+	public $id;
24
+	public $mal_id;
25
+	public $episodes = [
26
+		'length' => 0,
27
+		'total' => 0,
28
+		'watched' => '',
29
+	];
30
+	public $airing = [
31
+		'status' => '',
32
+		'started' => '',
33
+		'ended' => '',
34
+	];
35
+	public $anime;
36
+	public $watching_status;
37
+	public $notes;
38
+	public $rewatching;
39
+	public $rewatched;
40
+	public $user_rating;
41
+	public $private;
42
+}