diff --git a/app/views/anime/cover.php b/app/views/anime/cover.php index b43dc9d3..b4d52de8 100644 --- a/app/views/anime/cover.php +++ b/app/views/anime/cover.php @@ -24,7 +24,7 @@ " alt="" />
- +
@@ -85,7 +85,7 @@
-
html($item['anime']['type']) ?>
+
html($item['anime']['show_type']) ?>
html($item['airing']['status']) ?>
html($item['anime']['age_rating']) ?>
diff --git a/app/views/anime/details.php b/app/views/anime/details.php index eb6e333b..7e6d4fc6 100644 --- a/app/views/anime/details.php +++ b/app/views/anime/details.php @@ -38,7 +38,7 @@
-

+

diff --git a/app/views/anime/edit.php b/app/views/anime/edit.php index 08707720..a9ed6a6b 100644 --- a/app/views/anime/edit.php +++ b/app/views/anime/edit.php @@ -6,7 +6,7 @@ -

html(array_shift($item['anime']['titles'])) ?>

+

html($item['anime']['title']) ?>

html($title) ?>

diff --git a/app/views/anime/list.php b/app/views/anime/list.php index 2f67c626..08172ebd 100644 --- a/app/views/anime/list.php +++ b/app/views/anime/list.php @@ -42,15 +42,15 @@ - + - -
- + +
+ / 10 - + Episodes:
 /  @@ -83,8 +83,8 @@

html($item['notes']) ?>

- - + genres) ?> + genres) ?> diff --git a/composer.json b/composer.json index 82279651..48f5b5ec 100644 --- a/composer.json +++ b/composer.json @@ -39,6 +39,7 @@ "phpmd/phpmd": "^2.4", "phpstan/phpstan": "^0.9.1", "phpunit/phpunit": "^6.0", + "roave/security-advisories": "dev-master", "robmorgan/phinx": "^0.9.1", "sebastian/phpcpd": "^3.0", "spatie/phpunit-snapshot-assertions": "^1.2.0", diff --git a/src/API/Enum/AnimeWatchingStatus/Kitsu.php b/src/API/Enum/AnimeWatchingStatus/Kitsu.php index db3afcca..8bff6591 100644 --- a/src/API/Enum/AnimeWatchingStatus/Kitsu.php +++ b/src/API/Enum/AnimeWatchingStatus/Kitsu.php @@ -21,7 +21,7 @@ use Aviat\Ion\Enum; /** * Possible values for watching status for the current anime */ -class Kitsu extends Enum { +final class Kitsu extends Enum { const WATCHING = 'current'; const PLAN_TO_WATCH = 'planned'; const ON_HOLD = 'on_hold'; diff --git a/src/API/Enum/AnimeWatchingStatus/MAL.php b/src/API/Enum/AnimeWatchingStatus/MAL.php index b9d17c53..8d26bb72 100644 --- a/src/API/Enum/AnimeWatchingStatus/MAL.php +++ b/src/API/Enum/AnimeWatchingStatus/MAL.php @@ -21,7 +21,7 @@ use Aviat\Ion\Enum; /** * Possible values for watching status for the current anime */ -class MAL extends Enum { +final class MAL extends Enum { const WATCHING = 1; const COMPLETED = 2; const ON_HOLD = 3; diff --git a/src/API/Enum/AnimeWatchingStatus/Route.php b/src/API/Enum/AnimeWatchingStatus/Route.php index 4f834c55..05998b54 100644 --- a/src/API/Enum/AnimeWatchingStatus/Route.php +++ b/src/API/Enum/AnimeWatchingStatus/Route.php @@ -21,7 +21,7 @@ use Aviat\Ion\Enum as Enum; /** * Possible values for current watching status of anime */ -class Route extends Enum { +final class Route extends Enum { const ALL = 'all'; const WATCHING = 'watching'; const PLAN_TO_WATCH = 'plan_to_watch'; diff --git a/src/API/Enum/AnimeWatchingStatus/Title.php b/src/API/Enum/AnimeWatchingStatus/Title.php index ef3241cb..5a93d437 100644 --- a/src/API/Enum/AnimeWatchingStatus/Title.php +++ b/src/API/Enum/AnimeWatchingStatus/Title.php @@ -21,7 +21,7 @@ use Aviat\Ion\Enum as Enum; /** * Possible values for current watching status of anime */ -class Title extends Enum { +final class Title extends Enum { const ALL = 'All'; const WATCHING = 'Currently Watching'; const PLAN_TO_WATCH = 'Plan to Watch'; diff --git a/src/API/Enum/MangaReadingStatus/Kitsu.php b/src/API/Enum/MangaReadingStatus/Kitsu.php index 2c5f3d74..f7c157dc 100644 --- a/src/API/Enum/MangaReadingStatus/Kitsu.php +++ b/src/API/Enum/MangaReadingStatus/Kitsu.php @@ -21,7 +21,7 @@ use Aviat\Ion\Enum; /** * Possible values for current reading status of manga */ -class Kitsu extends Enum { +final class Kitsu extends Enum { const READING = 'current'; const PLAN_TO_READ = 'planned'; const DROPPED = 'dropped'; diff --git a/src/API/Enum/MangaReadingStatus/MAL.php b/src/API/Enum/MangaReadingStatus/MAL.php index 9fe1f767..469de135 100644 --- a/src/API/Enum/MangaReadingStatus/MAL.php +++ b/src/API/Enum/MangaReadingStatus/MAL.php @@ -21,7 +21,7 @@ use Aviat\Ion\Enum; /** * Possible values for watching status for the current anime */ -class MAL extends Enum { +final class MAL extends Enum { const READING = 'reading'; const COMPLETED = 'completed'; const ON_HOLD = 'onhold'; diff --git a/src/API/Enum/MangaReadingStatus/Route.php b/src/API/Enum/MangaReadingStatus/Route.php index f33f7ad1..ecd54366 100644 --- a/src/API/Enum/MangaReadingStatus/Route.php +++ b/src/API/Enum/MangaReadingStatus/Route.php @@ -16,12 +16,12 @@ namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus; -use Aviat\Ion\Enum as Enum; +use Aviat\Ion\Enum; /** * Possible values for current reading status of manga */ -class Route extends Enum { +final class Route extends Enum { const ALL = 'all'; const READING = 'reading'; const PLAN_TO_READ = 'plan_to_read'; diff --git a/src/API/Enum/MangaReadingStatus/Title.php b/src/API/Enum/MangaReadingStatus/Title.php index 292da0da..8188658f 100644 --- a/src/API/Enum/MangaReadingStatus/Title.php +++ b/src/API/Enum/MangaReadingStatus/Title.php @@ -16,12 +16,12 @@ namespace Aviat\AnimeClient\API\Enum\MangaReadingStatus; -use Aviat\Ion\Enum as Enum; +use Aviat\Ion\Enum; /** * Possible values for current reading status of manga */ -class Title extends Enum { +final class Title extends Enum { const ALL = 'All'; const READING = 'Currently Reading'; const PLAN_TO_READ = 'Plan to Read'; diff --git a/src/API/JsonAPI.php b/src/API/JsonAPI.php index c90c4b85..f9ef15b3 100644 --- a/src/API/JsonAPI.php +++ b/src/API/JsonAPI.php @@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\API; /** * Class encapsulating Json API data structure for a request or response */ -class JsonAPI { +final class JsonAPI { /** * The full data array diff --git a/src/API/Kitsu.php b/src/API/Kitsu.php index 3b485064..6f372bde 100644 --- a/src/API/Kitsu.php +++ b/src/API/Kitsu.php @@ -22,7 +22,7 @@ use DateTimeImmutable; /** * Data massaging helpers for the Kitsu API */ -class Kitsu { +final class Kitsu { const AUTH_URL = 'https://kitsu.io/api/oauth/token'; const AUTH_USER_ID_KEY = 'kitsu-auth-userid'; const AUTH_TOKEN_CACHE_KEY = 'kitsu-auth-token'; diff --git a/src/API/Kitsu/Auth.php b/src/API/Kitsu/Auth.php index 39a52362..e6386ff4 100644 --- a/src/API/Kitsu/Auth.php +++ b/src/API/Kitsu/Auth.php @@ -28,7 +28,7 @@ use Exception; /** * Kitsu API Authentication */ -class Auth { +final class Auth { use CacheTrait; use ContainerAware; @@ -37,14 +37,14 @@ class Auth { * * @var Model */ - protected $model; + private $model; /** * Session object * * @var \Aura\Session\Segment */ - protected $segment; + private $segment; /** * Constructor diff --git a/src/API/Kitsu/Enum/AnimeAiringStatus.php b/src/API/Kitsu/Enum/AnimeAiringStatus.php index 93577a5d..02a0bbdf 100644 --- a/src/API/Kitsu/Enum/AnimeAiringStatus.php +++ b/src/API/Kitsu/Enum/AnimeAiringStatus.php @@ -21,7 +21,7 @@ use Aviat\Ion\Enum as BaseEnum; /** * Status of when anime is being/was/will be aired */ -class AnimeAiringStatus extends BaseEnum { +final class AnimeAiringStatus extends BaseEnum { const NOT_YET_AIRED = 'Not Yet Aired'; const AIRING = 'Currently Airing'; const FINISHED_AIRING = 'Finished Airing'; diff --git a/src/API/Kitsu/KitsuRequestBuilder.php b/src/API/Kitsu/KitsuRequestBuilder.php index e36ee6f3..9fe30b91 100644 --- a/src/API/Kitsu/KitsuRequestBuilder.php +++ b/src/API/Kitsu/KitsuRequestBuilder.php @@ -18,7 +18,7 @@ namespace Aviat\AnimeClient\API\Kitsu; use Aviat\AnimeClient\API\APIRequestBuilder; -class KitsuRequestBuilder extends APIRequestBuilder { +final class KitsuRequestBuilder extends APIRequestBuilder { /** * The base url for api requests diff --git a/src/API/Kitsu/ListItem.php b/src/API/Kitsu/ListItem.php index aaa77c85..bb7be57b 100644 --- a/src/API/Kitsu/ListItem.php +++ b/src/API/Kitsu/ListItem.php @@ -25,39 +25,17 @@ use Aviat\AnimeClient\API\{ HummingbirdClient, ListItemInterface }; +use Aviat\AnimeClient\Types\AbstractType; use Aviat\Ion\Di\ContainerAware; use Aviat\Ion\Json; /** * CRUD operations for Kitsu list items */ -class ListItem implements ListItemInterface { +final class ListItem implements ListItemInterface { use ContainerAware; use KitsuTrait; - private function getAuthHeader() - { - $cache = $this->getContainer()->get('cache'); - $cacheItem = $cache->getItem('kitsu-auth-token'); - $sessionSegment = $this->getContainer() - ->get('session') - ->getSegment(SESSION_SEGMENT); - - if ($sessionSegment->get('auth_token') !== NULL) - { - $token = $sessionSegment->get('auth_token'); - return "bearer {$token}"; - } - - if ($cacheItem->isHit()) - { - $token = $cacheItem->get(); - return "bearer {$token}"; - } - - return FALSE; - } - public function create(array $data): Request { $body = [ @@ -134,7 +112,7 @@ class ListItem implements ListItemInterface { return Json::decode(wait($response->getBody())); } - public function update(string $id, array $data): Request + public function update(string $id, AbstractType $data): Request { $authHeader = $this->getAuthHeader(); $requestData = [ @@ -155,4 +133,25 @@ class ListItem implements ListItemInterface { return $request->getFullRequest(); } + + private function getAuthHeader() + { + $cache = $this->getContainer()->get('cache'); + $cacheItem = $cache->getItem('kitsu-auth-token'); + $sessionSegment = $this->getContainer() + ->get('session') + ->getSegment(SESSION_SEGMENT); + + if ($sessionSegment->get('auth_token') !== NULL) { + $token = $sessionSegment->get('auth_token'); + return "bearer {$token}"; + } + + if ($cacheItem->isHit()) { + $token = $cacheItem->get(); + return "bearer {$token}"; + } + + return FALSE; + } } \ No newline at end of file diff --git a/src/API/Kitsu/Model.php b/src/API/Kitsu/Model.php index 6d2077f1..63e2e021 100644 --- a/src/API/Kitsu/Model.php +++ b/src/API/Kitsu/Model.php @@ -36,17 +36,22 @@ use Aviat\AnimeClient\API\Kitsu\Transformer\{ MangaTransformer, MangaListTransformer }; +use Aviat\AnimeClient\Types\{ + Anime, + AnimeFormItem, + AnimeListItem +}; use Aviat\Ion\{Di\ContainerAware, Json}; /** * Kitsu API Model */ -class Model { +final class Model { use CacheTrait; use ContainerAware; use KitsuTrait; - protected const LIST_PAGE_SIZE = 100; + private const LIST_PAGE_SIZE = 100; /** * Class to map anime list items @@ -55,27 +60,27 @@ class Model { * * @var AnimeListTransformer */ - protected $animeListTransformer; + private $animeListTransformer; /** * @var AnimeTransformer */ - protected $animeTransformer; + private $animeTransformer; /** * @var ListItem */ - protected $listItem; + private $listItem; /** * @var MangaTransformer */ - protected $mangaTransformer; + private $mangaTransformer; /** * @var MangaListTransformer */ - protected $mangaListTransformer; + private $mangaListTransformer; /** * Constructor @@ -313,15 +318,15 @@ class Model { * Get information about a particular anime * * @param string $slug - * @return array + * @return Anime */ - public function getAnime(string $slug): array + public function getAnime(string $slug): Anime { $baseData = $this->getRawMediaData('anime', $slug); if (empty($baseData)) { - return []; + return new Anime(); } $transformed = $this->animeTransformer->transform($baseData); @@ -803,9 +808,9 @@ class Model { * Get the data for a specific list item, generally for editing * * @param string $listId - The unique identifier of that list item - * @return array + * @return mixed */ - public function getListItem(string $listId): array + public function getListItem(string $listId) { $baseData = $this->listItem->get($listId); $included = JsonAPI::organizeIncludes($baseData['included']); @@ -813,12 +818,12 @@ class Model { switch (TRUE) { - case in_array('anime', array_keys($included)): + case array_key_exists('anime', $included): // in_array('anime', array_keys($included)): $included = JsonAPI::inlineIncludedRelationships($included, 'anime'); $baseData['data']['included'] = $included; return $this->animeListTransformer->transform($baseData['data']); - case in_array('manga', array_keys($included)): + case array_key_exists('manga', $included): // in_array('manga', array_keys($included)): $included = JsonAPI::inlineIncludedRelationships($included, 'manga'); $baseData['data']['included'] = $included; $baseData['data']['manga'] = $baseData['included'][0]; @@ -832,10 +837,10 @@ class Model { /** * Modify a list item * - * @param array $data + * @param AnimeFormItem $data * @return Request */ - public function updateListItem(array $data): Request + public function updateListItem(AnimeFormItem $data): Request { return $this->listItem->update($data['id'], $data['data']); } diff --git a/src/API/Kitsu/Transformer/AnimeListTransformer.php b/src/API/Kitsu/Transformer/AnimeListTransformer.php index cd692caf..19b01952 100644 --- a/src/API/Kitsu/Transformer/AnimeListTransformer.php +++ b/src/API/Kitsu/Transformer/AnimeListTransformer.php @@ -17,21 +17,27 @@ namespace Aviat\AnimeClient\API\Kitsu\Transformer; use Aviat\AnimeClient\API\Kitsu; +use Aviat\AnimeClient\Types\{ + Anime, + AnimeFormItem, + AnimeFormItemData, + AnimeListItem +}; use Aviat\Ion\Transformer\AbstractTransformer; /** * Transformer for anime list */ -class AnimeListTransformer extends AbstractTransformer { +final class AnimeListTransformer extends AbstractTransformer { /** * Convert raw api response to a more * logical and workable structure * * @param array $item API library item - * @return array + * @return AnimeListItem */ - public function transform($item): array + public function transform($item): AnimeListItem { $included = $item['included']; $animeId = $item['relationships']['media']['data']['id']; @@ -66,7 +72,10 @@ class AnimeListTransformer extends AbstractTransformer { ? Kitsu::parseListItemStreamingLinks($included, $animeId) : []; - return [ + $titles = Kitsu::filterTitles($anime); + $title = array_shift($titles); + + return new AnimeListItem([ 'id' => $item['id'], 'mal_id' => $MALid, 'episodes' => [ @@ -81,24 +90,24 @@ class AnimeListTransformer extends AbstractTransformer { 'started' => $anime['startDate'], 'ended' => $anime['endDate'] ], - 'anime' => [ + 'anime' => new Anime([ 'id' => $animeId, 'age_rating' => $anime['ageRating'], - 'title' => $anime['canonicalTitle'], - 'titles' => Kitsu::filterTitles($anime), + 'title' => $title, + 'titles' => $titles, 'slug' => $anime['slug'], - 'type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(), - 'image' => $anime['posterImage']['small'], + 'show_type' => $this->string($anime['showType'])->upperCaseFirst()->__toString(), + 'cover_image' => $anime['posterImage']['small'], 'genres' => $genres, 'streaming_links' => $streamingLinks, - ], + ]), 'watching_status' => $item['attributes']['status'], 'notes' => $item['attributes']['notes'], 'rewatching' => (bool) $item['attributes']['reconsuming'], 'rewatched' => (int) $item['attributes']['reconsumeCount'], 'user_rating' => $rating, 'private' => $item['attributes']['private'] ?? FALSE, - ]; + ]); } /** @@ -106,24 +115,24 @@ class AnimeListTransformer extends AbstractTransformer { * api response format * * @param array $item Transformed library item - * @return array API library item + * @return AnimeFormItem API library item */ - public function untransform($item): array + public function untransform($item): AnimeFormItem { $privacy = (array_key_exists('private', $item) && $item['private']); $rewatching = (array_key_exists('rewatching', $item) && $item['rewatching']); - $untransformed = [ + $untransformed = new AnimeFormItem([ 'id' => $item['id'], 'mal_id' => $item['mal_id'] ?? NULL, - 'data' => [ + 'data' => new AnimeFormItemData([ 'status' => $item['watching_status'], 'reconsuming' => $rewatching, 'reconsumeCount' => $item['rewatched'], 'notes' => $item['notes'], 'private' => $privacy - ] - ]; + ]) + ]); if (is_numeric($item['episodes_watched']) && $item['episodes_watched'] > 0) { diff --git a/src/API/Kitsu/Transformer/AnimeTransformer.php b/src/API/Kitsu/Transformer/AnimeTransformer.php index 1d8a35bd..bb5059c6 100644 --- a/src/API/Kitsu/Transformer/AnimeTransformer.php +++ b/src/API/Kitsu/Transformer/AnimeTransformer.php @@ -17,31 +17,32 @@ namespace Aviat\AnimeClient\API\Kitsu\Transformer; use Aviat\AnimeClient\API\{JsonAPI, Kitsu}; +use Aviat\AnimeClient\Types\Anime; use Aviat\Ion\Transformer\AbstractTransformer; /** * Transformer for anime description page */ -class AnimeTransformer extends AbstractTransformer { +final class AnimeTransformer extends AbstractTransformer { /** * Convert raw api response to a more * logical and workable structure * * @param array $item API library item - * @return array + * @return Anime */ - public function transform($item): array + public function transform($item): Anime { - $item['included'] = JsonAPI::organizeIncludes($item['included']); $genres = $item['included']['categories'] ?? []; $item['genres'] = array_column($genres, 'title') ?? []; sort($item['genres']); $titles = Kitsu::filterTitles($item); + $title = array_shift($titles); - return [ + return new Anime([ 'age_rating' => $item['ageRating'], 'age_rating_guide' => $item['ageRatingGuide'], 'cover_image' => $item['posterImage']['small'], @@ -54,10 +55,10 @@ class AnimeTransformer extends AbstractTransformer { 'status' => Kitsu::getAiringStatus($item['startDate'], $item['endDate']), 'streaming_links' => Kitsu::parseStreamingLinks($item['included']), 'synopsis' => $item['synopsis'], - 'title' => $titles[0], + 'title' => $title, 'titles' => $titles, 'trailer_id' => $item['youtubeVideoId'], 'url' => "https://kitsu.io/anime/{$item['slug']}", - ]; + ]); } } \ No newline at end of file diff --git a/src/API/Kitsu/Transformer/MangaListTransformer.php b/src/API/Kitsu/Transformer/MangaListTransformer.php index b243bcac..60ce4d19 100644 --- a/src/API/Kitsu/Transformer/MangaListTransformer.php +++ b/src/API/Kitsu/Transformer/MangaListTransformer.php @@ -23,7 +23,7 @@ use Aviat\Ion\Transformer\AbstractTransformer; /** * Data transformation class for zippered Hummingbird manga */ -class MangaListTransformer extends AbstractTransformer { +final class MangaListTransformer extends AbstractTransformer { use StringWrapper; diff --git a/src/API/Kitsu/Transformer/MangaTransformer.php b/src/API/Kitsu/Transformer/MangaTransformer.php index 53465603..532b37a1 100644 --- a/src/API/Kitsu/Transformer/MangaTransformer.php +++ b/src/API/Kitsu/Transformer/MangaTransformer.php @@ -21,7 +21,7 @@ use Aviat\Ion\Transformer\AbstractTransformer; /** * Transformer for anime description page */ -class MangaTransformer extends AbstractTransformer { +final class MangaTransformer extends AbstractTransformer { /** * Convert raw api response to a more diff --git a/src/API/ListItemInterface.php b/src/API/ListItemInterface.php index bd252417..9fbcde48 100644 --- a/src/API/ListItemInterface.php +++ b/src/API/ListItemInterface.php @@ -17,6 +17,7 @@ namespace Aviat\AnimeClient\API; use Amp\Artax\Request; +use Aviat\AnimeClient\Types\AbstractType; /** * Common interface for anime and manga list item CRUD @@ -43,10 +44,10 @@ interface ListItemInterface { * Update a list item * * @param string $id - The id of the list item to update - * @param array $data - The data with which to update the list item + * @param AbstractType $data - The data with which to update the list item * @return Request */ - public function update(string $id, array $data): Request; + public function update(string $id, AbstractType $data): Request; /** * Delete a list item diff --git a/src/API/MAL.php b/src/API/MAL.php index 12343a28..332a721f 100644 --- a/src/API/MAL.php +++ b/src/API/MAL.php @@ -28,7 +28,7 @@ use Aviat\AnimeClient\API\Enum\{ /** * Constants and mappings for the My Anime List API */ -class MAL { +final class MAL { const AUTH_URL = 'https://myanimelist.net/api/account/verify_credentials.xml'; const BASE_URL = 'https://myanimelist.net/api/'; diff --git a/src/API/MAL/ListItem.php b/src/API/MAL/ListItem.php index 7df6fad0..09405394 100644 --- a/src/API/MAL/ListItem.php +++ b/src/API/MAL/ListItem.php @@ -20,12 +20,13 @@ use Amp\Artax\{FormBody, Request}; use Aviat\AnimeClient\API\{ XML }; +use Aviat\AnimeClient\Types\AbstractType; use Aviat\Ion\Di\ContainerAware; /** * CRUD operations for MAL list items */ -class ListItem { +final class ListItem { use ContainerAware; use MALTrait; @@ -84,11 +85,11 @@ class ListItem { * Update a list item * * @param string $id - * @param array $data + * @param AbstractType $data * @param string $type * @return Request */ - public function update(string $id, array $data, string $type = 'anime'): Request + public function update(string $id, AbstractType $data, string $type = 'anime'): Request { $config = $this->container->get('config'); diff --git a/src/API/MAL/MALRequestBuilder.php b/src/API/MAL/MALRequestBuilder.php index c7539729..40171c4a 100644 --- a/src/API/MAL/MALRequestBuilder.php +++ b/src/API/MAL/MALRequestBuilder.php @@ -21,7 +21,7 @@ use Aviat\AnimeClient\API\{ MAL as M }; -class MALRequestBuilder extends APIRequestBuilder { +final class MALRequestBuilder extends APIRequestBuilder { /** * The base url for api requests diff --git a/src/API/MAL/Model.php b/src/API/MAL/Model.php index 7c807f31..b8160e00 100644 --- a/src/API/MAL/Model.php +++ b/src/API/MAL/Model.php @@ -24,12 +24,13 @@ use Aviat\AnimeClient\API\MAL\{ }; use Aviat\AnimeClient\API\XML; use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus}; +use Aviat\AnimeClient\Types\{Anime, AnimeFormItem}; use Aviat\Ion\Di\ContainerAware; /** * MyAnimeList API Model */ -class Model { +final class Model { use ContainerAware; use MALTrait; @@ -147,11 +148,11 @@ class Model { /** * Update a list item * - * @param array $data + * @param AnimeFormItem $data * @param string $type "anime" or "manga" * @return Request */ - public function updateListItem(array $data, string $type = 'anime'): Request + public function updateListItem(AnimeFormItem $data, string $type = 'anime'): Request { $updateData = []; diff --git a/src/API/MAL/Transformer/AnimeListTransformer.php b/src/API/MAL/Transformer/AnimeListTransformer.php index 25d18c2c..af38f8e7 100644 --- a/src/API/MAL/Transformer/AnimeListTransformer.php +++ b/src/API/MAL/Transformer/AnimeListTransformer.php @@ -17,12 +17,13 @@ namespace Aviat\AnimeClient\API\MAL\Transformer; use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus; +use Aviat\AnimeClient\Types\{AnimeFormItem, AnimeFormItemData}; use Aviat\Ion\Transformer\AbstractTransformer; /** * Transformer for updating MAL List */ -class AnimeListTransformer extends AbstractTransformer { +final class AnimeListTransformer extends AbstractTransformer { /** * Identity transformation * @@ -38,16 +39,14 @@ class AnimeListTransformer extends AbstractTransformer { * Transform Kitsu episode data to MAL episode data * * @param array $item - * @return array + * @return AnimeFormItem */ - public function untransform(array $item): array + public function untransform(array $item): AnimeFormItem { - $map = [ + $map = new AnimeFormItem([ 'id' => $item['mal_id'], - 'data' => [] - ]; - - $data =& $item['data']; + 'data' => new AnimeFormItemData([]), + ]); foreach($item['data'] as $key => $value) { @@ -56,7 +55,7 @@ class AnimeListTransformer extends AbstractTransformer { case 'progress': $map['data']['episode'] = $value; break; - + case 'notes': $map['data']['comments'] = $value; break; diff --git a/src/API/MAL/Transformer/MangaListTransformer.php b/src/API/MAL/Transformer/MangaListTransformer.php index 2c04db77..b55f91fc 100644 --- a/src/API/MAL/Transformer/MangaListTransformer.php +++ b/src/API/MAL/Transformer/MangaListTransformer.php @@ -22,7 +22,7 @@ use Aviat\Ion\Transformer\AbstractTransformer; /** * Transformer for updating MAL List */ -class MangaListTransformer extends AbstractTransformer { +final class MangaListTransformer extends AbstractTransformer { /** * Identity transformation * diff --git a/src/API/Mapping/AnimeWatchingStatus.php b/src/API/Mapping/AnimeWatchingStatus.php index 8bc37712..8771881b 100644 --- a/src/API/Mapping/AnimeWatchingStatus.php +++ b/src/API/Mapping/AnimeWatchingStatus.php @@ -23,7 +23,7 @@ use Aviat\Ion\Enum; * Anime watching status mappings, among Kitsu, MAL, Page titles * and url route segments */ -class AnimeWatchingStatus extends Enum { +final class AnimeWatchingStatus extends Enum { const KITSU_TO_MAL = [ Kitsu::WATCHING => MAL::WATCHING, Kitsu::PLAN_TO_WATCH => MAL::PLAN_TO_WATCH, diff --git a/src/API/Mapping/MangaReadingStatus.php b/src/API/Mapping/MangaReadingStatus.php index 77d76609..4d9080d4 100644 --- a/src/API/Mapping/MangaReadingStatus.php +++ b/src/API/Mapping/MangaReadingStatus.php @@ -23,7 +23,7 @@ use Aviat\Ion\Enum; * Manga reading status mappings, among Kitsu, MAL, Page titles * and url route segments */ -class MangaReadingStatus extends Enum { +final class MangaReadingStatus extends Enum { const KITSU_TO_MAL = [ Kitsu::READING => MAL::READING, Kitsu::PLAN_TO_READ => MAL::PLAN_TO_READ, diff --git a/src/API/ParallelAPIRequest.php b/src/API/ParallelAPIRequest.php index f89b11d7..877cf94a 100644 --- a/src/API/ParallelAPIRequest.php +++ b/src/API/ParallelAPIRequest.php @@ -22,14 +22,14 @@ use function Amp\Promise\{all, wait}; /** * Class to simplify making and validating simultaneous requests */ -class ParallelAPIRequest { +final class ParallelAPIRequest { /** * Set of requests to make in parallel * * @var array */ - protected $requests = []; + private $requests = []; /** * Add a request @@ -76,9 +76,7 @@ class ParallelAPIRequest { { $promises[$key] = call(function () use ($client, $url) { $response = yield $client->request($url); - $body = yield $response->getBody(); - - return $body; + return yield $response->getBody(); }); } diff --git a/src/API/XML.php b/src/API/XML.php index 8908bbb0..eeedf0c9 100644 --- a/src/API/XML.php +++ b/src/API/XML.php @@ -21,7 +21,7 @@ use DOMDocument, DOMNode, DOMNodeList, InvalidArgumentException; /** * XML <=> PHP Array codec */ -class XML { +final class XML { /** * XML representation of the data diff --git a/src/Command/CacheClear.php b/src/Command/CacheClear.php index 81ff5d59..61f98ba0 100644 --- a/src/Command/CacheClear.php +++ b/src/Command/CacheClear.php @@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\Command; /** * Clears the API Cache */ -class CacheClear extends BaseCommand { +final class CacheClear extends BaseCommand { /** * Clear the API cache * diff --git a/src/Command/CachePrime.php b/src/Command/CachePrime.php index ae6cf5d3..871f8f70 100644 --- a/src/Command/CachePrime.php +++ b/src/Command/CachePrime.php @@ -19,7 +19,7 @@ namespace Aviat\AnimeClient\Command; /** * Clears the API Cache */ -class CachePrime extends BaseCommand { +final class CachePrime extends BaseCommand { /** * Clear, then prime the API cache * diff --git a/src/Command/SyncLists.php b/src/Command/SyncLists.php index c64d4194..4567a742 100644 --- a/src/Command/SyncLists.php +++ b/src/Command/SyncLists.php @@ -32,7 +32,7 @@ use DateTime; /** * Clears the API Cache */ -class SyncLists extends BaseCommand { +final class SyncLists extends BaseCommand { /** * Model for making requests to Kitsu API diff --git a/src/Controller/Anime.php b/src/Controller/Anime.php index 013c4a25..d1ccb05e 100644 --- a/src/Controller/Anime.php +++ b/src/Controller/Anime.php @@ -27,7 +27,7 @@ use Aviat\Ion\StringWrapper; /** * Controller for Anime-related pages */ -class Anime extends BaseController { +final class Anime extends BaseController { use StringWrapper; @@ -277,7 +277,7 @@ class Anime extends BaseController { $show_data = $this->model->getAnime($animeId); $characters = []; - if (empty($show_data)) + if ($show_data->title === '') { $this->notFound( $this->config->get('whose_list') . @@ -301,7 +301,7 @@ class Anime extends BaseController { 'title' => $this->formatTitle( $this->config->get('whose_list') . "'s Anime List", 'Anime', - $show_data['titles'][0] + $show_data->title ), 'characters' => $characters, 'show_data' => $show_data, diff --git a/src/Controller/AnimeCollection.php b/src/Controller/AnimeCollection.php index 520408f0..094f2120 100644 --- a/src/Controller/AnimeCollection.php +++ b/src/Controller/AnimeCollection.php @@ -26,7 +26,7 @@ use Aviat\Ion\Di\ContainerInterface; /** * Controller for Anime collection pages */ -class AnimeCollection extends BaseController { +final class AnimeCollection extends BaseController { /** * The anime collection model diff --git a/src/Controller/Character.php b/src/Controller/Character.php index 2619833a..d14b099a 100644 --- a/src/Controller/Character.php +++ b/src/Controller/Character.php @@ -23,7 +23,7 @@ use Aviat\Ion\ArrayWrapper; /** * Controller for character description pages */ -class Character extends BaseController { +final class Character extends BaseController { use ArrayWrapper; diff --git a/src/Controller/Index.php b/src/Controller/Index.php index 985dc92f..a797cf2c 100644 --- a/src/Controller/Index.php +++ b/src/Controller/Index.php @@ -25,7 +25,7 @@ use Aviat\Ion\View\HtmlView; /** * Controller for handling routes that don't fit elsewhere */ -class Index extends BaseController { +final class Index extends BaseController { /** * Purges the API cache diff --git a/src/Controller/Manga.php b/src/Controller/Manga.php index c6ed6de1..0c1ad65d 100644 --- a/src/Controller/Manga.php +++ b/src/Controller/Manga.php @@ -26,7 +26,7 @@ use Aviat\Ion\{Json, StringWrapper}; /** * Controller for manga list */ -class Manga extends Controller { +final class Manga extends Controller { use StringWrapper; diff --git a/src/Controller/MangaCollection.php b/src/Controller/MangaCollection.php index cbceefcc..a904d50e 100644 --- a/src/Controller/MangaCollection.php +++ b/src/Controller/MangaCollection.php @@ -26,7 +26,7 @@ use Aviat\Ion\Di\ContainerInterface; /** * Controller for manga collection pages */ -class MangaCollection extends BaseController { +final class MangaCollection extends BaseController { /** * The manga collection model diff --git a/src/Dispatcher.php b/src/Dispatcher.php index 19e17b35..d40e89a0 100644 --- a/src/Dispatcher.php +++ b/src/Dispatcher.php @@ -28,7 +28,7 @@ use Aviat\Ion\StringWrapper; /** * Basic routing/ dispatch */ -class Dispatcher extends RoutingBase { +final class Dispatcher extends RoutingBase { use StringWrapper; diff --git a/src/Helper/Menu.php b/src/Helper/Menu.php index 17a5e380..cdbc37c4 100644 --- a/src/Helper/Menu.php +++ b/src/Helper/Menu.php @@ -17,13 +17,14 @@ namespace Aviat\AnimeClient\Helper; use Aviat\AnimeClient\MenuGenerator; +use Aviat\Ion\Di\ContainerAware; /** * MenuGenerator helper wrapper */ -class Menu { +final class Menu { - use \Aviat\Ion\Di\ContainerAware; + use ContainerAware; /** * Create the html for the selected menu diff --git a/src/MenuGenerator.php b/src/MenuGenerator.php index b7c92da5..eaf51066 100644 --- a/src/MenuGenerator.php +++ b/src/MenuGenerator.php @@ -25,7 +25,7 @@ use Aviat\Ion\Exception\ConfigException; /** * Helper object to manage menu creation and selection */ -class MenuGenerator extends UrlGenerator { +final class MenuGenerator extends UrlGenerator { use ArrayWrapper; use StringWrapper; diff --git a/src/Model/API.php b/src/Model/API.php index e4501c90..a71273bb 100644 --- a/src/Model/API.php +++ b/src/Model/API.php @@ -44,7 +44,7 @@ class API { foreach ($array as $key => $item) { - $sort[$key] = $item[$sortKey]['titles'][0]; + $sort[$key] = $item[$sortKey]['title']; } array_multisort($sort, SORT_ASC, $array); diff --git a/src/Model/Anime.php b/src/Model/Anime.php index 3669002b..0b37bba4 100644 --- a/src/Model/Anime.php +++ b/src/Model/Anime.php @@ -18,13 +18,18 @@ namespace Aviat\AnimeClient\Model; use Aviat\AnimeClient\API\ParallelAPIRequest; use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus; +use Aviat\AnimeClient\Types\{ + Anime as AnimeType, + AnimeFormItem, + AnimeListItem, +}; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Json; /** * Model for handling requests dealing with the anime list */ -class Anime extends API { +final class Anime extends API { /** * Model for making requests to Kitsu API * @@ -93,9 +98,9 @@ class Anime extends API { * Get information about an anime from its slug * * @param string $slug - * @return array + * @return AnimeType */ - public function getAnime(string $slug): array + public function getAnime(string $slug): AnimeType { return $this->kitsuModel->getAnime($slug); } @@ -127,9 +132,9 @@ class Anime extends API { * for editing/updating that item * * @param string $itemId - * @return array + * @return AnimeListItem */ - public function getLibraryItem(string $itemId): array + public function getLibraryItem(string $itemId): AnimeListItem { return $this->kitsuModel->getListItem($itemId); } @@ -166,10 +171,10 @@ class Anime extends API { /** * Update a list entry * - * @param array $data + * @param AnimeFormItem $data * @return array */ - public function updateLibraryItem(array $data): array + public function updateLibraryItem(AnimeFormItem $data): array { $requester = new ParallelAPIRequest(); diff --git a/src/Model/AnimeCollection.php b/src/Model/AnimeCollection.php index 2af9de2c..ba578f0d 100644 --- a/src/Model/AnimeCollection.php +++ b/src/Model/AnimeCollection.php @@ -22,7 +22,7 @@ use PDO; /** * Model for getting anime collection data */ -class AnimeCollection extends Collection { +final class AnimeCollection extends Collection { /** * Anime API Model diff --git a/src/Model/Manga.php b/src/Model/Manga.php index b3ddcf41..85c050c7 100644 --- a/src/Model/Manga.php +++ b/src/Model/Manga.php @@ -27,7 +27,7 @@ use Aviat\Ion\Json; /** * Model for handling requests dealing with the manga list */ -class Manga extends API +final class Manga extends API { /** * Model for making requests to Kitsu API diff --git a/src/Model/MangaCollection.php b/src/Model/MangaCollection.php index a41b6618..f3d41968 100644 --- a/src/Model/MangaCollection.php +++ b/src/Model/MangaCollection.php @@ -22,7 +22,7 @@ use PDO; /** * Model for getting anime collection data */ -class MangaCollection extends Collection { +final class MangaCollection extends Collection { /** * Manga API Model diff --git a/src/Types/AbstractType.php b/src/Types/AbstractType.php new file mode 100644 index 00000000..bbb3ed41 --- /dev/null +++ b/src/Types/AbstractType.php @@ -0,0 +1,121 @@ + + * @copyright 2015 - 2018 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\Types; + +use ArrayAccess; +use LogicException; + +abstract class AbstractType implements ArrayAccess { + /** + * Sets the properties by using the constructor + * + * @param array $data + */ + public function __construct(array $data = []) + { + foreach ($data as $key => $value) { + $this->$key = $value; + } + } + + /** + * See if a property is set + * + * @param $name + * @return bool + */ + public function __isset($name): bool + { + return property_exists($this, $name); + } + + /** + * Set a property on the type object + * + * @param string $name + * @param mixed $value + * @return void + */ + public function __set($name, $value): void + { + if (!property_exists($this, $name)) { + $existing = json_encode($this); + + throw new LogicException("Trying to set non-existent property: '$name'. Existing properties: $existing"); + } + + $this->$name = $value; + } + + /** + * Get a property from the type object + * + * @param string $name + * @return mixed + */ + public function __get($name) + { + if (property_exists($this, $name)) { + return $this->$name; + } + + throw new LogicException("Trying to get non-existent property: '$name'"); + } + + /** + * Implementing ArrayAccess + * + * @param $offset + * @return bool + */ + public function offsetExists($offset): bool + { + return $this->__isset($offset); + } + + /** + * Implementing ArrayAccess + * + * @param $offset + * @return mixed + */ + public function offsetGet($offset) + { + return $this->__get($offset); + } + + /** + * Implementing ArrayAccess + * + * @param $offset + * @param $value + */ + public function offsetSet($offset, $value): void + { + $this->__set($offset, $value); + } + + /** + * Implementing ArrayAccess + * + * @param $offset + */ + public function offsetUnset($offset): void + { + // Do nothing! + } +} \ No newline at end of file diff --git a/src/Types/Anime.php b/src/Types/Anime.php new file mode 100644 index 00000000..d3fd573a --- /dev/null +++ b/src/Types/Anime.php @@ -0,0 +1,40 @@ + + * @copyright 2015 - 2018 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\Types; + +/** + * Type representing an Anime object for display + */ +final class Anime extends AbstractType { + public $age_rating; + public $age_rating_guide; + public $cover_image; + public $episode_count; + public $episode_length; + public $genres; + public $id; + public $included; + public $show_type; + public $slug; + public $status; + public $streaming_links; + public $synopsis; + public $title; + public $titles; + public $trailer_id; + public $url; +} \ No newline at end of file diff --git a/src/Types/AnimeFormItem.php b/src/Types/AnimeFormItem.php new file mode 100644 index 00000000..af02e058 --- /dev/null +++ b/src/Types/AnimeFormItem.php @@ -0,0 +1,26 @@ + + * @copyright 2015 - 2018 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\Types; + +/** + * Type representing an Anime object for display + */ +final class AnimeFormItem extends AbstractType { + public $data; + public $id; + public $mal_id; +} diff --git a/src/Types/AnimeFormItemData.php b/src/Types/AnimeFormItemData.php new file mode 100644 index 00000000..88eb2a13 --- /dev/null +++ b/src/Types/AnimeFormItemData.php @@ -0,0 +1,30 @@ + + * @copyright 2015 - 2018 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\Types; + +/** + * Type representing an Anime object for display + */ +final class AnimeFormItemData extends AbstractType { + public $notes; + public $private; + public $progress; + public $rating; + public $reconsumeCount; + public $reconsuming; + public $status; +} diff --git a/src/Types/AnimeListItem.php b/src/Types/AnimeListItem.php new file mode 100644 index 00000000..0e80b04d --- /dev/null +++ b/src/Types/AnimeListItem.php @@ -0,0 +1,42 @@ + + * @copyright 2015 - 2018 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @version 4.0 + * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient + */ + +namespace Aviat\AnimeClient\Types; + +/** + * Type representing an Anime object for display + */ +final class AnimeListItem extends AbstractType { + public $id; + public $mal_id; + public $episodes = [ + 'length' => 0, + 'total' => 0, + 'watched' => '', + ]; + public $airing = [ + 'status' => '', + 'started' => '', + 'ended' => '', + ]; + public $anime; + public $watching_status; + public $notes; + public $rewatching; + public $rewatched; + public $user_rating; + public $private; +}