Merge branch 'develop' into fix-sort
Some checks are pending
timw4mail/HummingBirdAnimeClient/pipeline/pr-develop Build started...

This commit is contained in:
Timothy Warren 2022-01-07 17:02:19 -05:00
commit 42fa458058
38 changed files with 300 additions and 164 deletions

View File

@ -9,8 +9,8 @@ use ConsoleKit\Console;
$GLOBALS['_SERVER']['HTTP_HOST'] = 'localhost';
define('APP_DIR', __DIR__ . '/app');
define('TEMPLATE_DIR', APP_DIR . '/templates');
const APP_DIR = __DIR__ . '/app';
const TEMPLATE_DIR = APP_DIR . '/templates';
// -----------------------------------------------------------------------------
// Start console script

View File

@ -25,7 +25,7 @@ setlocale(LC_CTYPE, 'en_US');
// Load composer autoloader
require_once __DIR__ . '/vendor/autoload.php';
Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // all errors except deprecated notices
Debugger::$strictMode = E_ALL & ~E_DEPRECATED; // all errors except deprecated notices
Debugger::$showBar = false;
Debugger::enable(Debugger::DEVELOPMENT, __DIR__ . '/app/logs');

View File

@ -154,7 +154,7 @@ abstract class APIRequestBuilder {
* Set a request header
*
* @param string $name
* @param string $value
* @param string|null $value
* @return self
*/
public function setHeader(string $name, string $value = NULL): self

View File

@ -70,7 +70,7 @@ abstract class AbstractListItem {
* Delete a list item
*
* @param string $id - The id of the list item to delete
* @return Request
* @return Request|null
*/
abstract public function delete(string $id):?Request;
}

View File

@ -207,7 +207,7 @@ final class Model
*
* @param FormItem $data
* @param string $type - Them media type (anime/manga)
* @return Request
* @return Request|null
*/
public function incrementListItem(FormItem $data, string $type): ?Request
{
@ -225,7 +225,7 @@ final class Model
*
* @param FormItem $data
* @param string $type - Them media type (anime/manga)
* @return Request
* @return Request|null
*/
public function updateListItem(FormItem $data, string $type): ?Request
{
@ -244,7 +244,7 @@ final class Model
*
* @param string $malId - The id of the list item to remove
* @param string $type - Them media type (anime/manga)
* @return Request
* @return Request|null
*/
public function deleteListItem(string $malId, string $type): ?Request
{
@ -262,7 +262,7 @@ final class Model
*
* @param string $malId
* @param string $type - The media type (anime/manga)
* @return string
* @return string|null
*/
public function getListIdFromMalId(string $malId, string $type): ?string
{
@ -306,7 +306,7 @@ final class Model
*
* @param string $malId
* @param string $type
* @return string
* @return string|null
*/
private function getMediaIdFromMalId(string $malId, string $type = 'ANIME'): ?string
{

View File

@ -257,24 +257,18 @@ final class RequestBuilder extends APIRequestBuilder {
$validResponseCodes = [200, 201];
$logger = $this->container->getLogger('anilist-request');
if ($logger !== NULL)
{
$logger->debug('Anilist response', [
$logger?->debug('Anilist response', [
'status' => $response->getStatus(),
'reason' => $response->getReason(),
'body' => $response->getBody(),
'headers' => $response->getHeaders(),
//'requestHeaders' => $request->getHeaders(),
]);
}
if ( ! \in_array($response->getStatus(), $validResponseCodes, TRUE))
{
if ($logger !== NULL)
{
$logger->warning('Non 200 response for POST api call', (array)$response->getBody());
}
$logger?->warning('Non 200 response for POST api call', (array)$response->getBody());
}
$rawBody = wait($response->getBody()->buffer());

View File

@ -24,6 +24,7 @@ use Aviat\AnimeClient\Types\{AnimeListItem, FormItem};
use Aviat\Ion\Transformer\AbstractTransformer;
use DateTime;
use DateTimeInterface;
class AnimeListTransformer extends AbstractTransformer {
@ -57,7 +58,7 @@ class AnimeListTransformer extends AbstractTransformer {
: AnimeWatchingStatus::ANILIST_TO_KITSU[$item['status']],
'updatedAt' => (new DateTime())
->setTimestamp($item['updatedAt'])
->format(DateTime::W3C)
->format(DateTimeInterface::W3C)
],
]);
}

View File

@ -25,6 +25,7 @@ use Aviat\AnimeClient\Types\FormItem;
use Aviat\Ion\Transformer\AbstractTransformer;
use DateTime;
use DateTimeInterface;
class MangaListTransformer extends AbstractTransformer {
@ -58,7 +59,7 @@ class MangaListTransformer extends AbstractTransformer {
: MangaReadingStatus::ANILIST_TO_KITSU[$item['status']],
'updatedAt' => (new DateTime())
->setTimestamp($item['updatedAt'])
->format(DateTime::W3C),
->format(DateTimeInterface::W3C),
]
]);
}

View File

@ -19,10 +19,8 @@ namespace Aviat\AnimeClient\API\Anilist\Types;
use Aviat\AnimeClient\Types\AbstractType;
class MediaListEntry extends AbstractType {
/**
* @var int|string
*/
public $id;
public int|string $id;
public ?string $notes;

View File

@ -12,7 +12,7 @@ union ActivityUnion = ListActivity | MessageActivity | TextActivity
union LikeableUnion = ActivityReply | ListActivity | MessageActivity | TextActivity | Thread | ThreadComment
"Notification union type"
union NotificationUnion = ActivityLikeNotification | ActivityMentionNotification | ActivityMessageNotification | ActivityReplyLikeNotification | ActivityReplyNotification | ActivityReplySubscribedNotification | AiringNotification | FollowingNotification | RelatedMediaAdditionNotification | ThreadCommentLikeNotification | ThreadCommentMentionNotification | ThreadCommentReplyNotification | ThreadCommentSubscribedNotification | ThreadLikeNotification
union NotificationUnion = ActivityLikeNotification | ActivityMentionNotification | ActivityMessageNotification | ActivityReplyLikeNotification | ActivityReplyNotification | ActivityReplySubscribedNotification | AiringNotification | FollowingNotification | MediaDataChangeNotification | MediaDeletionNotification | MediaMergeNotification | RelatedMediaAdditionNotification | ThreadCommentLikeNotification | ThreadCommentMentionNotification | ThreadCommentReplyNotification | ThreadCommentSubscribedNotification | ThreadLikeNotification
"Notification for when a activity is liked"
type ActivityLikeNotification {
@ -227,6 +227,8 @@ type AniChartUser {
type Character {
"The character's age. Note this is a string, not an int, it may contain further text and additional ages."
age: String
"The characters blood type"
bloodType: String
"The character's birth date"
dateOfBirth: FuzzyDate
"A general description of the character"
@ -262,7 +264,7 @@ type Character {
name: CharacterName
"The url for the character page on the AniList website"
siteUrl: String
updatedAt: Int @deprecated(reason : "No data available")
updatedAt: Int @deprecated(reason: "No data available")
}
type CharacterConnection {
@ -314,15 +316,21 @@ type CharacterName {
middle: String
"The character's full name in their native language"
native: String
"The currently authenticated users preferred name language. Default romaji for non-authenticated"
userPreferred: String
}
"A submission for a character that features in an anime or manga"
type CharacterSubmission {
"Data Mod assigned to handle the submission"
assignee: User
"Character that the submission is referencing"
character: Character
createdAt: Int
"The id of the submission"
id: Int!
"Whether the submission is locked"
locked: Boolean
"Inner details of submission status"
notes: String
source: String
@ -543,6 +551,7 @@ type InternalPage {
sort: [AiringSort]
): [AiringSchedule]
characterSubmissions(
assigneeId: Int,
characterId: Int,
"The order the results will be returned in"
sort: [SubmissionSort],
@ -654,6 +663,8 @@ type InternalPage {
id_not_in: [Int],
"Filter by if the media's intended for 18+ adult audiences"
isAdult: Boolean,
"If the media is officially licensed or a self-published doujin release"
isLicensed: Boolean,
"Filter media by sites with a online streaming or reading license"
licensedBy: String,
"Filter media by sites with a online streaming or reading license"
@ -772,6 +783,7 @@ type InternalPage {
userName: String
): [MediaList]
mediaSubmissions(
assigneeId: Int,
mediaId: Int,
"The order the results will be returned in"
sort: [SubmissionSort],
@ -864,7 +876,7 @@ type InternalPage {
"Filter by user who created the recommendation"
userId: Int
): [Recommendation]
reports: [Report]
reports(reportedId: Int, reporterId: Int): [Report]
reviews(
"Filter by Review id"
id: Int,
@ -906,6 +918,7 @@ type InternalPage {
sort: [StaffSort]
): [Staff]
staffSubmissions(
assigneeId: Int,
"The order the results will be returned in"
sort: [SubmissionSort],
staffId: Int,
@ -958,9 +971,15 @@ type InternalPage {
"Filter by the user id of the thread's creator"
userId: Int
): [Thread]
userBlockSearch(
"Filter by search query"
search: String
): [User]
users(
"Filter by the user id"
id: Int,
"Filter to moderators only if true"
isModerator: Boolean,
"Filter by the name of the user"
name: String,
"Filter by search query"
@ -1073,6 +1092,8 @@ type Media {
isAdult: Boolean
"If the media is marked as favourite by the current authenticated user"
isFavourite: Boolean!
"If the media is blocked from being added to favourites"
isFavouriteBlocked: Boolean!
"If the media is officially licensed or a self-published doujin release"
isLicensed: Boolean
"Locked media may not be added to lists our favorited. This may be due to the entry pending for deletion or other reasons."
@ -1120,7 +1141,7 @@ type Media {
siteUrl: String
"Source type the media was adapted from."
source(
"Provide 2 to use new version 2 of sources enum"
"Provide 2 or 3 to use new version 2 or 3 of sources enum"
version: Int
): MediaSource
"The staff who produced the media"
@ -1205,6 +1226,40 @@ type MediaCoverImage {
medium: String
}
"Notification for when a media entry's data was changed in a significant way impacting users' list tracking"
type MediaDataChangeNotification {
"The reason for the media data change"
context: String
"The time the notification was created at"
createdAt: Int
"The id of the Notification"
id: Int!
"The media that received data changes"
media: Media
"The id of the media that received data changes"
mediaId: Int!
"The reason for the media data change"
reason: String
"The type of notification"
type: NotificationType
}
"Notification for when a media tracked in a user's list is deleted from the site"
type MediaDeletionNotification {
"The reason for the media deletion"
context: String
"The time the notification was created at"
createdAt: Int
"The title of the deleted media"
deletedMediaTitle: String
"The id of the Notification"
id: Int!
"The reason for the media deletion"
reason: String
"The type of notification"
type: NotificationType
}
"Media connection edge"
type MediaEdge {
"Media specific character name"
@ -1298,13 +1353,13 @@ type MediaList {
"List of anime or manga"
type MediaListCollection {
"A map of media list entry arrays grouped by custom lists"
customLists(asArray: Boolean): [[MediaList]] @deprecated(reason : "Not GraphQL spec compliant, use lists field instead.")
customLists(asArray: Boolean): [[MediaList]] @deprecated(reason: "Not GraphQL spec compliant, use lists field instead.")
"If there is another chunk"
hasNextChunk: Boolean
"Grouped media list entries"
lists: [MediaListGroup]
"A map of media list entry arrays grouped by status"
statusLists(asArray: Boolean): [[MediaList]] @deprecated(reason : "Not GraphQL spec compliant, use lists field instead.")
statusLists(asArray: Boolean): [[MediaList]] @deprecated(reason: "Not GraphQL spec compliant, use lists field instead.")
"The owner of the list"
user: User
}
@ -1330,10 +1385,10 @@ type MediaListOptions {
"The score format the user is using for media lists"
scoreFormat: ScoreFormat
"The list theme options for both lists"
sharedTheme: Json @deprecated(reason : "No longer used")
sharedTheme: Json @deprecated(reason: "No longer used")
"If the shared theme should be used instead of the individual list themes"
sharedThemeEnabled: Boolean @deprecated(reason : "No longer used")
useLegacyLists: Boolean @deprecated(reason : "No longer used")
sharedThemeEnabled: Boolean @deprecated(reason: "No longer used")
useLegacyLists: Boolean @deprecated(reason: "No longer used")
}
"A user's list options for anime or manga lists"
@ -1349,7 +1404,27 @@ type MediaListTypeOptions {
"If the completed sections of the list should be separated by format"
splitCompletedSectionByFormat: Boolean
"The list theme options"
theme: Json @deprecated(reason : "This field has not yet been fully implemented and may change without warning")
theme: Json @deprecated(reason: "This field has not yet been fully implemented and may change without warning")
}
"Notification for when a media entry is merged into another for a user who had it on their list"
type MediaMergeNotification {
"The reason for the media data change"
context: String
"The time the notification was created at"
createdAt: Int
"The title of the deleted media"
deletedMediaTitles: [String]
"The id of the Notification"
id: Int!
"The media that was merged into"
media: Media
"The id of the media that was merged into"
mediaId: Int!
"The reason for the media merge"
reason: String
"The type of notification"
type: NotificationType
}
"The ranking of a media in a particular time span and format compared to other media"
@ -1374,7 +1449,7 @@ type MediaRank {
"A media's statistics"
type MediaStats {
airingProgression: [AiringProgression] @deprecated(reason : "Replaced by MediaTrends")
airingProgression: [AiringProgression] @deprecated(reason: "Replaced by MediaTrends")
scoreDistribution: [ScoreDistribution]
statusDistribution: [StatusDistribution]
}
@ -1393,12 +1468,16 @@ type MediaStreamingEpisode {
"Media submission"
type MediaSubmission {
"Data Mod assigned to handle the submission"
assignee: User
changes: [String]
characters: [MediaSubmissionComparison]
createdAt: Int
externalLinks: [MediaExternalLink]
"The id of the submission"
id: Int!
"Whether the submission is locked"
locked: Boolean
media: Media
notes: String
relations: [MediaEdge]
@ -1458,6 +1537,8 @@ type MediaTag {
name: String!
"The relevance ranking of the tag out of the 100 for this media"
rank: Int
"The user who submitted the tag"
userId: Int
}
"The official titles of the media in various languages"
@ -1738,6 +1819,8 @@ type Mutation {
comment: String,
"The comment id, required for updating"
id: Int,
"If the comment tree should be locked. (Mod Only)"
locked: Boolean,
"The id of thread comment to reply to"
parentCommentId: Int,
"The id of thread the comment belongs to"
@ -1872,6 +1955,8 @@ type Mutation {
rowOrder: String,
"The user's list scoring system"
scoreFormat: ScoreFormat,
"The language the user wants to see staff and character names in"
staffNameLanguage: UserStaffNameLanguage,
"Timezone offset format: -?HH:MM"
timezone: String,
"User's title language"
@ -2094,6 +2179,8 @@ type Page {
id_not_in: [Int],
"Filter by if the media's intended for 18+ adult audiences"
isAdult: Boolean,
"If the media is officially licensed or a self-published doujin release"
isLicensed: Boolean,
"Filter media by sites with a online streaming or reading license"
licensedBy: String,
"Filter media by sites with a online streaming or reading license"
@ -2368,6 +2455,8 @@ type Page {
users(
"Filter by the user id"
id: Int,
"Filter to moderators only if true"
isModerator: Boolean,
"Filter by the name of the user"
name: String,
"Filter by search query"
@ -2618,6 +2707,8 @@ type Query {
id_not_in: [Int],
"Filter by if the media's intended for 18+ adult audiences"
isAdult: Boolean,
"If the media is officially licensed or a self-published doujin release"
isLicensed: Boolean,
"Filter media by sites with a online streaming or reading license"
licensedBy: String,
"Filter media by sites with a online streaming or reading license"
@ -2958,6 +3049,8 @@ type Query {
User(
"Filter by the user id"
id: Int,
"Filter to moderators only if true"
isModerator: Boolean,
"Filter by the name of the user"
name: String,
"Filter by search query"
@ -3014,6 +3107,7 @@ type RelatedMediaAdditionNotification {
}
type Report {
cleared: Boolean
"When the entry data was created"
createdAt: Int
id: Int!
@ -3179,6 +3273,8 @@ type SiteTrendEdge {
type Staff {
"The person's age in years"
age: Int
"The persons blood type"
bloodType: String
"Media the actor voiced characters in. (Same data as characters with media as node instead of characters)"
characterMedia(
onList: Boolean,
@ -3218,7 +3314,7 @@ type Staff {
"If the staff member is blocked from being added to favourites"
isFavouriteBlocked: Boolean!
"The primary language the staff member dub's in"
language: StaffLanguage @deprecated(reason : "Replaced with languageV2")
language: StaffLanguage @deprecated(reason: "Replaced with languageV2")
"The primary language of the staff member. Current values: Japanese, English, Korean, Italian, Spanish, Portuguese, French, German, Hebrew, Hungarian, Chinese, Arabic, Filipino, Catalan"
languageV2: String
"Notes for site moderators"
@ -3247,7 +3343,7 @@ type Staff {
submissionStatus: Int
"Submitter for the submission"
submitter: User
updatedAt: Int @deprecated(reason : "No data available")
updatedAt: Int @deprecated(reason: "No data available")
"[startYear, endYear] (If the 2nd value is not present staff is still active)"
yearsActive: [Int]
}
@ -3291,6 +3387,8 @@ type StaffName {
middle: String
"The person's full name in their native language"
native: String
"The currently authenticated users preferred name language. Default romaji for non-authenticated"
userPreferred: String
}
"Voice actor role for a character"
@ -3314,9 +3412,13 @@ type StaffStats {
"A submission for a staff that features in an anime or manga"
type StaffSubmission {
"Data Mod assigned to handle the submission"
assignee: User
createdAt: Int
"The id of the submission"
id: Int!
"Whether the submission is locked"
locked: Boolean
"Inner details of submission status"
notes: String
source: String
@ -3511,6 +3613,8 @@ type ThreadComment {
id: Int!
"If the currently authenticated user liked the comment"
isLiked: Boolean
"If the comment tree is locked and may not receive replies or edits"
isLocked: Boolean
"The amount of likes the comment has"
likeCount: Int!
"The users who liked the comment"
@ -3651,6 +3755,8 @@ type User {
"The user's banner images"
bannerImage: String
bans: Json
"When the user's account was created. (Does not exist for accounts created before 2020)"
createdAt: Int
"Custom donation badge text"
donatorBadge: String
"The donation tier of the user"
@ -3670,18 +3776,22 @@ type User {
isFollowing: Boolean
"The user's media list options"
mediaListOptions: MediaListOptions
"The user's moderator roles if they are a site moderator"
moderatorRoles: [ModRole]
"If the user is a moderator or data moderator"
moderatorStatus: String
moderatorStatus: String @deprecated(reason: "Deprecated. Replaced with moderatorRoles field.")
"The name of the user"
name: String!
"The user's general options"
options: UserOptions
"The user's previously used names."
previousNames: [UserPreviousName]
"The url for the user page on the AniList website"
siteUrl: String
"The users anime & manga list statistics"
statistics: UserStatisticTypes
"The user's statistics"
stats: UserStats @deprecated(reason : "Deprecated. Replaced with statistics field.")
stats: UserStats @deprecated(reason: "Deprecated. Replaced with statistics field.")
"The number of unread notifications the user has"
unreadNotificationCount: Int
"When the user's data was last updated"
@ -3747,7 +3857,9 @@ type UserModData {
alts: [User]
bans: Json
counts: Json
email: String
ip: Json
privacy: Int
}
"A user's general options"
@ -3762,12 +3874,24 @@ type UserOptions {
notificationOptions: [NotificationOption]
"Profile highlight color (blue, purple, pink, orange, red, green, gray)"
profileColor: String
"The language the user wants to see staff and character names in"
staffNameLanguage: UserStaffNameLanguage
"The user's timezone offset (Auth user only)"
timezone: String
"The language the user wants to see media titles in"
titleLanguage: UserTitleLanguage
}
"A user's previous name"
type UserPreviousName {
"When the user first changed from this name."
createdAt: Int
"A previous name of the user."
name: String
"When the user most recently changed from this name."
updatedAt: Int
}
type UserReleaseYearStatistic {
chaptersRead: Int!
count: Int!
@ -4127,24 +4251,36 @@ enum MediaSort {
"Source type the media was adapted from"
enum MediaSource {
"Version 2 only. Japanese Anime"
"Version 2+ only. Japanese Anime"
ANIME
"Version 2 only. Self-published works"
"Version 3 only. Comics excluding manga"
COMIC
"Version 2+ only. Self-published works"
DOUJINSHI
"Version 3 only. Games excluding video games"
GAME
"Written work published in volumes"
LIGHT_NOVEL
"Version 3 only. Live action media such as movies or TV show"
LIVE_ACTION
"Asian comic book"
MANGA
"Version 2 only. Written works not published in volumes"
"Version 3 only. Multimedia project"
MULTIMEDIA_PROJECT
"Version 2+ only. Written works not published in volumes"
NOVEL
"An original production not based of another work"
ORIGINAL
"Other"
OTHER
"Version 3 only. Picture book"
PICTURE_BOOK
"Video game"
VIDEO_GAME
"Video game driven primary by text and narrative"
VISUAL_NOVEL
"Version 3 only. Written works published online"
WEB_NOVEL
}
"The current releasing status of the media"
@ -4198,6 +4334,36 @@ enum ModActionType {
RESET
}
"Mod role enums"
enum ModRole {
"An AniList administrator"
ADMIN
"An anime data moderator"
ANIME_DATA
"A community moderator"
COMMUNITY
"An AniList developer"
DEVELOPER
"A discord community moderator"
DISCORD_COMMUNITY
"A lead anime data moderator"
LEAD_ANIME_DATA
"A lead community moderator"
LEAD_COMMUNITY
"A head developer of AniList"
LEAD_DEVELOPER
"A lead manga data moderator"
LEAD_MANGA_DATA
"A lead social media moderator"
LEAD_SOCIAL_MEDIA
"A manga data moderator"
MANGA_DATA
"A retired moderator"
RETIRED
"A social media moderator"
SOCIAL_MEDIA
}
"Notification type enum"
enum NotificationType {
"A user has liked your activity"
@ -4216,6 +4382,12 @@ enum NotificationType {
AIRING
"A user has followed you"
FOLLOWING
"An anime or manga has had a data change that affects how a user may track it in their lists"
MEDIA_DATA_CHANGE
"An anime or manga on the user's list has been deleted from the site"
MEDIA_DELETION
"Anime or manga entries on the user's list have been merged into a single entry"
MEDIA_MERGE
"A new anime or manga has been added to the site where its related media is on the user's list"
RELATED_MEDIA_ADDITION
"A user has liked your forum comment"
@ -4399,6 +4571,16 @@ enum UserSort {
WATCHED_TIME_DESC
}
"The language the user wants to see staff and character names in"
enum UserStaffNameLanguage {
"The staff or character's name in their native language"
NATIVE
"The romanization of the staff or character's native name"
ROMAJI
"The romanization of the staff or character's native name, with western name ordering"
ROMAJI_WESTERN
}
"User statistics sort enum"
enum UserStatisticsSort {
COUNT
@ -4427,6 +4609,14 @@ enum UserTitleLanguage {
ROMAJI_STYLISED
}
"ISO 3166-1 alpha-2 country code"
scalar CountryCode
"8 digit long date integer (YYYYMMDD). Unknown dates represented by 0. E.g. 2016: 20160000, May 1976: 19760500"
scalar FuzzyDateInt
scalar Json
input AiringScheduleInput {
airingAt: Int
episode: Int
@ -4521,12 +4711,3 @@ input StaffNameInput {
"The person's full name in their native language"
native: String
}
scalar Json
"ISO 3166-1 alpha-2 country code"
scalar CountryCode
"8 digit long date integer (YYYYMMDD). Unknown dates represented by 0. E.g. 2016: 20160000, May 1976: 19760500"
scalar FuzzyDateInt

View File

@ -17,7 +17,6 @@
namespace Aviat\AnimeClient\API;
use Psr\SimpleCache\CacheInterface;
use Psr\SimpleCache\InvalidArgumentException;
/**
* Helper methods for dealing with the Cache

View File

@ -23,7 +23,6 @@ use const Aviat\AnimeClient\SESSION_SEGMENT;
use Aviat\AnimeClient\Kitsu as K;
use Aviat\AnimeClient\API\CacheTrait;
use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
use Aviat\Ion\Event;
/**
@ -129,11 +128,11 @@ final class Auth {
{
if (PHP_SAPI === 'cli')
{
return $this->segment->get('auth_token', NULL)
?? $this->cache->get(K::AUTH_TOKEN_CACHE_KEY, NULL);
return $this->segment->get('auth_token')
?? $this->cache->get(K::AUTH_TOKEN_CACHE_KEY);
}
return $this->segment->get('auth_token', NULL);
return $this->segment->get('auth_token');
}
/**
@ -146,7 +145,7 @@ final class Auth {
if (PHP_SAPI === 'cli')
{
return $this->segment->get('refresh_token')
?? $this->cache->get(K::AUTH_TOKEN_REFRESH_CACHE_KEY, NULL);
?? $this->cache->get(K::AUTH_TOKEN_REFRESH_CACHE_KEY);
}
return $this->segment->get('refresh_token');

View File

@ -16,17 +16,10 @@
namespace Aviat\AnimeClient\API\Kitsu;
use Aviat\Ion\Di\Exception\ContainerException;
use Aviat\Ion\Di\Exception\NotFoundException;
use function Amp\Promise\wait;
use function Aviat\AnimeClient\getResponse;
use Amp\Http\Client\Request;
use Aviat\AnimeClient\API\AbstractListItem;
use Aviat\AnimeClient\Types\FormItemData;
use Aviat\Ion\Di\ContainerAware;
use Aviat\Ion\Json;
use Throwable;

View File

@ -44,6 +44,7 @@ use Aviat\Ion\{
use Generator;
use function Amp\Promise\wait;
use function Aviat\AnimeClient\getApiClient;
use const Aviat\AnimeClient\SESSION_SEGMENT;
/**
* Kitsu API Model
@ -707,9 +708,14 @@ final class Model {
$rawData = Json::decode($json);
$data = $rawData['data']['findProfileBySlug']['library']['all'] ?? [];
$page = $data['pageInfo'];
$page = $data['pageInfo'] ?? [];
if (empty($data))
{
// Clear session, in case the error is an invalid token.
$segment = $this->container->get('session')
->getSegment(SESSION_SEGMENT);
$segment->clear();
// @TODO Proper Error logging
dump($rawData);
die();
@ -719,7 +725,7 @@ final class Model {
yield $emit($data['nodes']);
if ($page['hasNextPage'] === FALSE)
if ($page['hasNextPage'] !== TRUE)
{
break;
}

View File

@ -18,7 +18,6 @@ namespace Aviat\AnimeClient\API\Kitsu;
use Amp\Http\Client\Request;
use Aviat\AnimeClient\Types\FormItem;
use Aviat\Banker\Exception\InvalidArgumentException;
/**
* Kitsu API calls that mutate data, C/U/D parts of CRUD

View File

@ -192,16 +192,13 @@ final class RequestBuilder extends APIRequestBuilder {
$request = $this->setUpRequest($type, $url, $options);
$response = getResponse($request);
if ($logger !== NULL)
{
$logger->debug('Kitsu API Response', [
$logger?->debug('Kitsu API Response', [
'status' => $response->getStatus(),
'reason' => $response->getReason(),
'body' => $response->getBody(),
'headers' => $response->getHeaders(),
'requestHeaders' => $request->getHeaders(),
]);
}
return $response;
}

View File

@ -27,7 +27,7 @@ trait RequestBuilderTrait {
* Set the request builder object
*
* @param RequestBuilder $requestBuilder
* @return $this
* @return RequestBuilderTrait|ListItem|Model
*/
public function setRequestBuilder(RequestBuilder $requestBuilder): self
{

View File

@ -136,7 +136,7 @@ final class AnimeTransformer extends AbstractTransformer {
'show_type' => $base['subtype'],
'status' => Kitsu::getAiringStatus($base['startDate'], $base['endDate']),
'streaming_links' => Kitsu::parseStreamingLinks($base['streamingLinks']['nodes'] ?? []),
'synopsis' => $base['description']['en'],
'synopsis' => $base['description']['en'] ?? '',
'title' => $title,
'titles' => $titles,
'titles_more' => $titles_more,

View File

@ -16,7 +16,6 @@
namespace Aviat\AnimeClient\Command;
use Aviat\AnimeClient\Kitsu;
use Aviat\Ion\Di\Exception\ContainerException;
use Aviat\Ion\Di\Exception\NotFoundException;
use function Aviat\AnimeClient\clearCache;

View File

@ -203,7 +203,7 @@ final class SyncLists extends BaseCommand {
*
* @param string $type
* @param array $data
* @return array|array[]
* @return array
*/
protected function compare(string $type, array $data): array
{

View File

@ -375,10 +375,10 @@ class Controller {
* @param array $data
* @param HtmlView|NULL $view
* @param int $code
* @throws InvalidArgumentException
* @return void
*@throws InvalidArgumentException
*/
protected function outputHTML(string $template, array $data = [], $view = NULL, int $code = 200): void
protected function outputHTML(string $template, array $data = [], HtmlView $view = NULL, int $code = 200): void
{
if (NULL === $view)
{

View File

@ -66,15 +66,13 @@ final class Anime extends BaseController {
/**
* Show a portion, or all of the anime list
*
* @param string|int $status - The section of the list
* @param int|string $status - The section of the list
* @param string|null $view - List or cover view
* @throws ContainerException
* @throws NotFoundException
* @return void
* @throws InvalidArgumentException
* @throws Throwable
* @return void
*/
public function index($status = KitsuWatchingStatus::WATCHING, ?string $view = NULL): void
public function index(int|string $status = KitsuWatchingStatus::WATCHING, ?string $view = NULL): void
{
if ( ! in_array($status, [
'all',
@ -178,7 +176,7 @@ final class Anime extends BaseController {
* @param string $id
* @param string $status
*/
public function edit(string $id, $status = 'all'): void
public function edit(string $id, string $status = 'all'): void
{
$this->checkAuth();

View File

@ -239,8 +239,6 @@ final class AnimeCollection extends BaseController {
* Update a collection item
*
* @param array $data
* @throws ContainerException
* @throws NotFoundException
*/
protected function update(array $data): void
{

View File

@ -78,8 +78,6 @@ final class History extends BaseController {
'url_type' => 'anime',
]);
// $this->outputJSON($this->animeModel->getHistory());
// return;
$this->outputHTML('history', [
'title' => $this->formatTitle(
$this->config->get('whose_list') . "'s Anime List",
@ -98,8 +96,6 @@ final class History extends BaseController {
'url_type' => 'manga',
]);
// $this->outputJSON($this->mangaModel->getHistory());
// return;
$this->outputHTML('history', [
'title' => $this->formatTitle(
$this->config->get('whose_list') . "'s Manga List",

View File

@ -16,8 +16,6 @@
namespace Aviat\AnimeClient\Controller;
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
use function Amp\Promise\wait;
use function Aviat\AnimeClient\getResponse;
use function Aviat\AnimeClient\createPlaceholderImage;
@ -39,7 +37,7 @@ final class Images extends BaseController {
* @return void
* @throws Throwable
*/
public function cache(string $type, string $file, $display = TRUE): void
public function cache(string $type, string $file, bool $display = TRUE): void
{
$currentUrl = (string)$this->request->getUri();

View File

@ -64,10 +64,10 @@ final class Manga extends Controller {
*
* @param string $status
* @param string $view
* @throws InvalidArgumentException
* @return void
*@throws InvalidArgumentException
*/
public function index($status = 'all', $view = ''): void
public function index(string $status = 'all', string $view = ''): void
{
if ( ! in_array($status, [
'all',

View File

@ -52,8 +52,6 @@ final class People extends BaseController {
*
* @param string $slug
* @return void
* @throws ContainerException
* @throws NotFoundException
*/
public function index(string $slug): void
{

View File

@ -16,6 +16,8 @@
namespace Aviat\AnimeClient;
use Aviat\AnimeClient\Enum\EventType;
use Aviat\Ion\Event;
use Aviat\Ion\Json;
use Aura\Router\{
Map,
@ -27,7 +29,6 @@ use Aviat\AnimeClient\API\FailedResponseException;
use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Friend;
use Aviat\Ion\Type\StringType;
use JetBrains\PhpStorm\ArrayShape;
use LogicException;
use ReflectionException;
@ -117,7 +118,7 @@ final class Dispatcher extends RoutingBase {
* @return void
* @throws ReflectionException
*/
public function __invoke($route = NULL): void
public function __invoke(object $route = NULL): void
{
$logger = $this->container->getLogger();
@ -136,7 +137,7 @@ final class Dispatcher extends RoutingBase {
{
// If not route was matched, return an appropriate http
// error message
$errorRoute = (array)$this->getErrorParams();
$errorRoute = $this->getErrorParams();
$controllerName = DEFAULT_CONTROLLER;
$actionMethod = $errorRoute['action_method'];
$params = $errorRoute['params'];
@ -278,17 +279,14 @@ final class Dispatcher extends RoutingBase {
*/
protected function call(string $controllerName, string $method, array $params): void
{
$logger = $this->container->getLogger('default');
$logger = $this->container->getLogger();
try
{
$controller = new $controllerName($this->container);
// Run the appropriate controller method
if ($logger !== NULL)
{
$logger->debug('Dispatcher - controller arguments', $params);
}
$logger?->debug('Dispatcher - controller arguments', $params);
$params = array_values($params);
$controller->$method(...$params);
@ -360,7 +358,7 @@ final class Dispatcher extends RoutingBase {
}
/**
* Select controller based on the current url, and apply its relevent routes
* Select controller based on the current url, and apply its relevant routes
*
* @return array
*/

View File

@ -16,17 +16,8 @@
namespace Aviat\AnimeClient\Model;
use Aviat\AnimeClient\API\ParallelAPIRequest;
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
use Aviat\AnimeClient\Types\{
Anime as AnimeType,
FormItem,
AnimeListItem
};
use Aviat\Ion\Json;
use Throwable;
use function is_array;
use Aviat\AnimeClient\Types\Anime as AnimeType;
/**
* Model for handling requests dealing with the anime list
@ -64,7 +55,7 @@ class Anime extends API {
{
$data = $this->kitsuModel->getFullOrganizedAnimeList();
foreach($data as $section => &$list)
foreach($data as &$list)
{
$this->sortByName($list, 'anime');
}

View File

@ -578,7 +578,7 @@ final class AnimeCollection extends Collection {
* @param string $animeId The current anime
* @return void
*/
private function updateGenres($animeId): void
private function updateGenres(string $animeId): void
{
if ($this->db === NULL)
{

View File

@ -46,8 +46,6 @@ class Util {
* Set up the Util class
*
* @param ContainerInterface $container
* @throws ContainerException
* @throws NotFoundException
*/
public function __construct(ContainerInterface $container)
{

View File

@ -45,10 +45,10 @@ class Config implements ConfigInterface {
/**
* Does the config item exist?
*
* @param string|int|array $key
* @param array|int|string $key
* @return bool
*/
public function has($key): bool
public function has(array|int|string $key): bool
{
return $this->map->hasKey($key);
}
@ -60,7 +60,7 @@ class Config implements ConfigInterface {
* @return mixed
* @throws ConfigException
*/
public function get($key = NULL)
public function get(array|string $key = NULL): mixed
{
if (\is_array($key))
{
@ -73,10 +73,10 @@ class Config implements ConfigInterface {
/**
* Remove a config value
*
* @param string|array $key
* @param array|string $key
* @return void
*/
public function delete($key): void
public function delete(array|string $key): void
{
if (\is_array($key))
{
@ -92,12 +92,12 @@ class Config implements ConfigInterface {
/**
* Set a config value
*
* @param integer|string|array $key
* @param array|integer|string $key
* @param mixed $value
* @throws InvalidArgumentException
* @return ConfigInterface
*@throws InvalidArgumentException
*/
public function set($key, $value): ConfigInterface
public function set(array|int|string $key, mixed $value): ConfigInterface
{
if (\is_array($key))
{

View File

@ -23,10 +23,10 @@ interface ConfigInterface {
/**
* Does the config item exist?
*
* @param string|int|array $key
* @param array|int|string $key
* @return bool
*/
public function has($key): bool;
public function has(array|int|string $key): bool;
/**
* Get a config value
@ -34,23 +34,23 @@ interface ConfigInterface {
* @param array|string|null $key
* @return mixed
*/
public function get($key = NULL);
public function get(array|string $key = NULL): mixed;
/**
* Set a config value
*
* @param integer|string|array $key
* @param array|integer|string $key
* @param mixed $value
* @throws \InvalidArgumentException
* @return ConfigInterface
* @throws \InvalidArgumentException
*/
public function set($key, $value): self;
public function set(array|int|string $key, mixed $value): self;
/**
* Remove a config value
*
* @param string|array $key
* @param array|string $key
* @return void
*/
public function delete($key): void;
public function delete(array|string $key): void;
}

View File

@ -51,7 +51,7 @@ abstract class Enum {
* @return boolean
* @throws ReflectionException
*/
public static function isValid($key): bool
public static function isValid(mixed $key): bool
{
$values = array_values(static::getConstList());
return in_array($key, $values, TRUE);

View File

@ -31,7 +31,7 @@ class Friend {
* Object to create a friend of
* @var mixed
*/
private $_friend_;
private mixed $_friend_;
/**
* Reflection class of the object
@ -46,7 +46,7 @@ class Friend {
* @throws InvalidArgumentException
* @throws \ReflectionException
*/
public function __construct($obj)
public function __construct(mixed $obj)
{
if ( ! \is_object($obj))
{
@ -63,7 +63,7 @@ class Friend {
* @param string $key
* @return mixed
*/
public function __get(string $key)
public function __get(string $key): mixed
{
if ($this->__isset($key))
{
@ -96,7 +96,7 @@ class Friend {
* @param mixed $value
* @return void
*/
public function __set(string $key, $value)
public function __set(string $key, mixed $value)
{
if ($this->__isset($key))
{

View File

@ -93,7 +93,7 @@ class HttpView implements HttpViewInterface{
* @param string|string[] $value
* @return HttpView
*/
public function addHeader(string $name, $value): self
public function addHeader(string $name, array|string $value): self
{
$this->response = $this->response->withHeader($name, $value);
return $this;
@ -105,7 +105,7 @@ class HttpView implements HttpViewInterface{
* @param mixed $string
* @return HttpViewInterface
*/
public function setOutput($string): HttpViewInterface
public function setOutput(mixed $string): HttpViewInterface
{
$this->response->getBody()->write($string);

View File

@ -37,7 +37,7 @@ interface ViewInterface {
* @param mixed $string
* @return ViewInterface
*/
public function setOutput($string): self;
public function setOutput(mixed $string): self;
/**
* Append additional output.
@ -54,7 +54,7 @@ interface ViewInterface {
* @param string|string[] $value
* @return ViewInterface
*/
public function addHeader(string $name, $value): self;
public function addHeader(string $name, array|string $value): self;
/**
* Get the current output as a string. Does not

View File

@ -20,7 +20,7 @@ use Aviat\Ion\Config;
class ConfigTest extends IonTestCase {
protected $config;
protected Config $config;
public function setUp(): void
{
@ -66,12 +66,6 @@ class ConfigTest extends IonTestCase {
$this->assertEquals('great', $this->config->get(['apple', 'sauce', 'is']), "Array argument get for config failed.");
}
public function testConfigBadSet(): void
{
$this->expectException('InvalidArgumentException');
$this->config->set(NULL, FALSE);
}
public function dataConfigDelete(): array
{
return [