diff --git a/CHANGELOG.md b/CHANGELOG.md
index f20fc455..21bb4913 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,8 @@
# Changelog
+## Version 5.2
+* Updated PHP requirement to 8
+
## Version 5.1
* Added session check, so when coming back to a page, if the session is expired, the page will refresh.
* Updated logging config so that much fewer, much smaller files are generated.
diff --git a/Jenkinsfile b/Jenkinsfile
index 48232ea7..0abe3756 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -34,6 +34,13 @@ pipeline {
sh 'php ./vendor/bin/phpunit --colors=never'
}
}
+ stage('Code Cleanliness') {
+ agent any
+ steps {
+ sh "php8 ./vendor/bin/phpstan analyse -c phpstan.neon -n --no-ansi --no-progress --error-format=checkstyle | awk '{\$1=\$1;print}' > build/logs/checkstyle-result.xml"
+ recordIssues(tools: [checkStyle(reportEncoding: 'UTF-8')])
+ }
+ }
stage('Coverage') {
agent any
steps {
@@ -43,6 +50,7 @@ pipeline {
cloverReportDir: '',
cloverReportFileName: 'build/logs/clover.xml',
])
+ junit 'build/logs/junit.xml'
}
}
}
diff --git a/README.md b/README.md
index 4bf489cf..062c4a97 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
Update your anime/manga list on Kitsu.io and Anilist
[![Build Status](https://travis-ci.com/timw4mail/HummingBirdAnimeClient.svg?branch=master)](https://travis-ci.com/github/timw4mail/HummingBirdAnimeClient)
-[![Build Status](https://jenkins.timshomepage.net/buildStatus/icon?job=timw4mail/HummingBirdAnimeClient/develop)](https://jenkins.timshomepage.net/job/timw4mail/HummingBirdAnimeClient/develop)
+[![Build Status](https://jenkins.timshome.page/buildStatus/icon?job=timw4mail/HummingBirdAnimeClient/develop)](https://jenkins.timshome.page/job/timw4mail/job/HummingBirdAnimeClient/job/develop/)
[[Hosted Example](https://list.timshomepage.net)]
@@ -31,7 +31,7 @@ Update your anime/manga list on Kitsu.io and Anilist
### Requirements
-* PHP 7.4+
+* PHP 8
* PDO SQLite or PDO PostgreSQL (For collection tab)
* GD extension for caching images
diff --git a/build/phpunit.xml b/build/phpunit.xml
index 02c0a25e..a27b5804 100644
--- a/build/phpunit.xml
+++ b/build/phpunit.xml
@@ -17,7 +17,9 @@
../tests/Ion
-
+
+
+
diff --git a/index.php b/index.php
index 2e72e99e..ca9a24a5 100644
--- a/index.php
+++ b/index.php
@@ -64,7 +64,7 @@ if (array_key_exists('timezone', $checkedConfig) && ! empty($checkedConfig['time
{
date_default_timezone_set($checkedConfig['timezone']);
}
-else if ($timezone !== '')
+else if (is_string($timezone) && $timezone !== '')
{
date_default_timezone_set($timezone);
}
diff --git a/phpstan.neon b/phpstan.neon
index 7f460fb1..2fa40512 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -2,17 +2,19 @@ parameters:
checkGenericClassInNonGenericObjectType: false
checkMissingIterableValueType: false
inferPrivatePropertyTypeFromConstructor: true
- level: 7
- autoload_files:
- - %rootDir%/../../../tests/mocks.php
+ level: 8
paths:
- src
- ./console
- index.php
ignoreErrors:
- - '#Access to an undefined property Aviat\\\Ion\\\Friend::\$[a-zA-Z0-9_]+#'
- - '#Call to an undefined method Aviat\\\Ion\\\Friend::[a-zA-Z0-9_]+\(\)#'
+ - "#Offset 'fields' does not exist on array#"
+ - '#Function imagepalletetotruecolor not found#'
- '#Call to an undefined method Aura\\\Html\\\HelperLocator::[a-zA-Z0-9_]+\(\)#'
- - '#Property Amp\\Artax\\Internal\\RequestCycle::\$[a-zA-Z0-9_]+#'
+ - '#Call to an undefined method Query\\QueryBuilderInterface::[a-zA-Z0-9_]+\(\)#'
excludes_analyse:
- - tests/mocks.php
\ No newline at end of file
+ - tests/mocks.php
+ - vendor
+ # These are objects that basically can return anything
+ universalObjectCratesClasses:
+ - Aviat\Ion\Friend
diff --git a/src/AnimeClient/API/APIRequestBuilder.php b/src/AnimeClient/API/APIRequestBuilder.php
index 99d6274b..8b832090 100644
--- a/src/AnimeClient/API/APIRequestBuilder.php
+++ b/src/AnimeClient/API/APIRequestBuilder.php
@@ -116,10 +116,9 @@ abstract class APIRequestBuilder {
* Set the request body
*
* @param FormBody|string $body
- * @throws \TypeError
* @return self
*/
- public function setBody($body): self
+ public function setBody(FormBody|string $body): self
{
$this->request->setBody($body);
return $this;
@@ -129,7 +128,6 @@ abstract class APIRequestBuilder {
* Set body as form fields
*
* @param array $fields Mapping of field names to values
- * @throws \TypeError
* @return self
*/
public function setFormFields(array $fields): self
@@ -293,74 +291,6 @@ abstract class APIRequestBuilder {
return $this;
}
- /**
- * Create a GraphQL query and return the Request object
- *
- * @param string $name
- * @param array $variables
- * @return Request
- */
- public function queryRequest(string $name, array $variables = []): Request
- {
- $file = realpath("{$this->filePath}/Queries/{$name}.graphql");
- if ( ! file_exists($file))
- {
- throw new LogicException('GraphQL query file does not exist.');
- }
-
- $query = file_get_contents($file);
- $body = [
- 'query' => $query
- ];
-
- if ( ! empty($variables))
- {
- $body['variables'] = [];
- foreach($variables as $key => $val)
- {
- $body['variables'][$key] = $val;
- }
- }
-
- return $this->setUpRequest('POST', $this->baseUrl, [
- 'body' => $body,
- ]);
- }
-
- /**
- * Create a GraphQL mutation request, and return the Request object
- *
- * @param string $name
- * @param array $variables
- * @return Request
- * @throws Throwable
- */
- public function mutateRequest (string $name, array $variables = []): Request
- {
- $file = "{$this->filePath}/Mutations/{$name}.graphql";
- if ( ! file_exists($file))
- {
- throw new LogicException('GraphQL mutation file does not exist.');
- }
-
- $query = file_get_contents($file);
- $body = [
- 'query' => $query
- ];
-
- if (!empty($variables)) {
- $body['variables'] = [];
- foreach ($variables as $key => $val)
- {
- $body['variables'][$key] = $val;
- }
- }
-
- return $this->setUpRequest('POST', $this->baseUrl, [
- 'body' => $body,
- ]);
- }
-
/**
* Create the full request url
*
diff --git a/src/AnimeClient/API/Anilist/RequestBuilder.php b/src/AnimeClient/API/Anilist/RequestBuilder.php
index a6958a12..a7f4c1e8 100644
--- a/src/AnimeClient/API/Anilist/RequestBuilder.php
+++ b/src/AnimeClient/API/Anilist/RequestBuilder.php
@@ -31,6 +31,7 @@ use const Aviat\AnimeClient\USER_AGENT;
use Aviat\AnimeClient\API\APIRequestBuilder;
use LogicException;
+use Throwable;
final class RequestBuilder extends APIRequestBuilder {
use ContainerAware;
@@ -117,7 +118,7 @@ final class RequestBuilder extends APIRequestBuilder {
*/
public function runQuery(string $name, array $variables = []): array
{
- $file = realpath(__DIR__ . "/Queries/{$name}.graphql");
+ $file = __DIR__ . "/Queries/{$name}.graphql";
if ( ! file_exists($file))
{
throw new LogicException('GraphQL query file does not exist.');
@@ -150,8 +151,8 @@ final class RequestBuilder extends APIRequestBuilder {
*/
public function mutateRequest (string $name, array $variables = []): Request
{
- $file = realpath(__DIR__ . "/Mutations/{$name}.graphql");
- if (!file_exists($file))
+ $file = __DIR__ . "/Mutations/{$name}.graphql";
+ if ( ! file_exists($file))
{
throw new LogicException('GraphQL mutation file does not exist.');
}
diff --git a/src/AnimeClient/API/Anilist/Transformer/AnimeListTransformer.php b/src/AnimeClient/API/Anilist/Transformer/AnimeListTransformer.php
index b09ecb9e..ffb82c13 100644
--- a/src/AnimeClient/API/Anilist/Transformer/AnimeListTransformer.php
+++ b/src/AnimeClient/API/Anilist/Transformer/AnimeListTransformer.php
@@ -27,7 +27,7 @@ use DateTime;
class AnimeListTransformer extends AbstractTransformer {
- public function transform($item): AnimeListItem
+ public function transform(array|object $item): AnimeListItem
{
return AnimeListItem::from([]);
}
diff --git a/src/AnimeClient/API/Anilist/Transformer/MangaListTransformer.php b/src/AnimeClient/API/Anilist/Transformer/MangaListTransformer.php
index da2112d3..e1e47a79 100644
--- a/src/AnimeClient/API/Anilist/Transformer/MangaListTransformer.php
+++ b/src/AnimeClient/API/Anilist/Transformer/MangaListTransformer.php
@@ -28,7 +28,7 @@ use DateTime;
class MangaListTransformer extends AbstractTransformer {
- public function transform($item)
+ public function transform(array|object $item): MangaListItem
{
return MangaListItem::from([]);
}
diff --git a/src/AnimeClient/API/CacheTrait.php b/src/AnimeClient/API/CacheTrait.php
index e8d940ad..a7c0d111 100644
--- a/src/AnimeClient/API/CacheTrait.php
+++ b/src/AnimeClient/API/CacheTrait.php
@@ -58,10 +58,9 @@ trait CacheTrait {
* @param string $key
* @param callable $primer
* @param array|null $primeArgs
- * @return mixed|null
- * @throws InvalidArgumentException
+ * @return mixed
*/
- public function getCached(string $key, callable $primer, ?array $primeArgs = [])
+ public function getCached(string $key, callable $primer, ?array $primeArgs = []): mixed
{
$value = $this->cache->get($key, NULL);
diff --git a/src/AnimeClient/API/Kitsu/Auth.php b/src/AnimeClient/API/Kitsu/Auth.php
index 54d5de7c..0d0b5c5e 100644
--- a/src/AnimeClient/API/Kitsu/Auth.php
+++ b/src/AnimeClient/API/Kitsu/Auth.php
@@ -26,10 +26,6 @@ use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
use Aviat\Ion\Event;
-use Psr\SimpleCache\InvalidArgumentException;
-
-use Throwable;
-
/**
* Kitsu API Authentication
*/
@@ -55,8 +51,6 @@ final class Auth {
* Constructor
*
* @param ContainerInterface $container
- * @throws ContainerException
- * @throws NotFoundException
*/
public function __construct(ContainerInterface $container)
{
@@ -66,7 +60,7 @@ final class Auth {
->getSegment(SESSION_SEGMENT);
$this->model = $container->get('kitsu-model');
- Event::on('::unauthorized::', [$this, 'reAuthenticate'], []);
+ Event::on('::unauthorized::', [$this, 'reAuthenticate']);
}
/**
@@ -75,7 +69,6 @@ final class Auth {
*
* @param string $password
* @return boolean
- * @throws Throwable
*/
public function authenticate(string $password): bool
{
@@ -90,9 +83,8 @@ final class Auth {
/**
* Make the call to re-authenticate with the existing refresh token
*
- * @param string $refreshToken
+ * @param string|null $refreshToken
* @return boolean
- * @throws Throwable|InvalidArgumentException
*/
public function reAuthenticate(?string $refreshToken = NULL): bool
{
@@ -112,7 +104,6 @@ final class Auth {
* Check whether the current user is authenticated
*
* @return boolean
- * @throws InvalidArgumentException
*/
public function isAuthenticated(): bool
{
@@ -133,7 +124,6 @@ final class Auth {
* Retrieve the authentication token from the session
*
* @return string
- * @throws InvalidArgumentException
*/
public function getAuthToken(): ?string
{
@@ -150,7 +140,6 @@ final class Auth {
* Retrieve the refresh token
*
* @return string|null
- * @throws InvalidArgumentException
*/
private function getRefreshToken(): ?string
{
@@ -166,11 +155,10 @@ final class Auth {
/**
* Save the new authentication information
*
- * @param $auth
+ * @param array|false $auth
* @return bool
- * @throws InvalidArgumentException
*/
- private function storeAuth($auth): bool
+ private function storeAuth(array|false $auth): bool
{
if (FALSE !== $auth)
{
diff --git a/src/AnimeClient/API/Kitsu/Model.php b/src/AnimeClient/API/Kitsu/Model.php
index acfef90f..c91e7633 100644
--- a/src/AnimeClient/API/Kitsu/Model.php
+++ b/src/AnimeClient/API/Kitsu/Model.php
@@ -37,12 +37,11 @@ use Aviat\AnimeClient\Enum\MediaType;
use Aviat\AnimeClient\Kitsu as K;
use Aviat\AnimeClient\Types\Anime;
use Aviat\AnimeClient\Types\MangaPage;
-use Aviat\Banker\Exception\InvalidArgumentException;
use Aviat\Ion\{
Di\ContainerAware,
Json
};
-use Throwable;
+use Generator;
use function Amp\Promise\wait;
use function Aviat\AnimeClient\getApiClient;
@@ -91,7 +90,6 @@ final class Model {
* @param string $username
* @param string $password
* @return bool|array
- * @throws Throwable
*/
public function authenticate(string $username, string $password)
{
@@ -134,7 +132,6 @@ final class Model {
*
* @param string $token
* @return bool|array
- * @throws Throwable
*/
public function reAuthenticate(string $token)
{
@@ -174,7 +171,6 @@ final class Model {
*
* @param string|null $username
* @return string
- * @throws \Psr\SimpleCache\InvalidArgumentException
*/
public function getUserIdByUsername(string $username = NULL): string
{
@@ -210,7 +206,6 @@ final class Model {
*
* @param string $slug
* @return array
- * @throws InvalidArgumentException
*/
public function getPerson(string $slug): array
{
@@ -289,8 +284,6 @@ final class Model {
* Retrieve the data for the anime watch history page
*
* @return array
- * @throws InvalidArgumentException
- * @throws Throwable
*/
public function getAnimeHistory(): array
{
@@ -315,7 +308,6 @@ final class Model {
*
* @param string $status - The watching status to filter the list with
* @return array
- * @throws InvalidArgumentException
*/
public function getAnimeList(string $status): array
{
@@ -354,7 +346,6 @@ final class Model {
*
* @param string $status - Optional status to filter by
* @return int
- * @throws InvalidArgumentException
*/
public function getAnimeListCount(string $status = '') : int
{
@@ -365,8 +356,6 @@ final class Model {
* Get all the anime entries, that are organized for output to html
*
* @return array
- * @throws ReflectionException
- * @throws InvalidArgumentException
*/
public function getFullOrganizedAnimeList(): array
{
@@ -434,8 +423,6 @@ final class Model {
* Retrieve the data for the manga read history page
*
* @return array
- * @throws InvalidArgumentException
- * @throws Throwable
*/
public function getMangaHistory(): array
{
@@ -458,7 +445,6 @@ final class Model {
*
* @param string $status - The reading status by which to filter the list
* @return array
- * @throws InvalidArgumentException
*/
public function getMangaList(string $status): array
{
@@ -497,7 +483,6 @@ final class Model {
*
* @param string $status - Optional status to filter by
* @return int
- * @throws InvalidArgumentException
*/
public function getMangaListCount(string $status = '') : int
{
@@ -508,8 +493,6 @@ final class Model {
* Get all Manga lists
*
* @return array
- * @throws ReflectionException
- * @throws InvalidArgumentException
*/
public function getFullOrganizedMangaList(): array
{
@@ -638,8 +621,6 @@ final class Model {
*
* @param string $type
* @return array
- * @throws InvalidArgumentException
- * @throws Throwable
*/
public function getSyncList(string $type): array
{
@@ -831,7 +812,7 @@ final class Model {
});
}
- private function getPages(callable $method, ...$args): ?\Generator
+ private function getPages(callable $method, mixed ...$args): ?Generator
{
$items = $method(...$args);
diff --git a/src/AnimeClient/API/Kitsu/MutationTrait.php b/src/AnimeClient/API/Kitsu/MutationTrait.php
index 846b04a3..0fbc30b4 100644
--- a/src/AnimeClient/API/Kitsu/MutationTrait.php
+++ b/src/AnimeClient/API/Kitsu/MutationTrait.php
@@ -32,8 +32,7 @@ trait MutationTrait {
* Create a list item
*
* @param array $data
- * @return Request
- * @throws InvalidArgumentException
+ * @return Request|null
*/
public function createListItem(array $data): ?Request
{
diff --git a/src/AnimeClient/API/Kitsu/RequestBuilder.php b/src/AnimeClient/API/Kitsu/RequestBuilder.php
index a69b6853..999b0794 100644
--- a/src/AnimeClient/API/Kitsu/RequestBuilder.php
+++ b/src/AnimeClient/API/Kitsu/RequestBuilder.php
@@ -26,7 +26,6 @@ use Amp\Http\Client\Request;
use Amp\Http\Client\Response;
use Aviat\AnimeClient\Kitsu as K;
use Aviat\AnimeClient\API\APIRequestBuilder;
-use Aviat\AnimeClient\API\FailedResponseException;
use Aviat\AnimeClient\Enum\EventType;
use Aviat\Ion\Di\ContainerAware;
use Aviat\Ion\Di\ContainerInterface;
@@ -157,7 +156,6 @@ final class RequestBuilder extends APIRequestBuilder {
* @param string $name
* @param array $variables
* @return array
- * @throws Throwable
*/
public function mutate(string $name, array $variables = []): array
{
@@ -181,7 +179,6 @@ final class RequestBuilder extends APIRequestBuilder {
* @param string $url
* @param array $options
* @return Response
- * @throws \Throwable
*/
public function getResponse(string $type, string $url, array $options = []): Response
{
@@ -200,15 +197,79 @@ final class RequestBuilder extends APIRequestBuilder {
return $response;
}
+ /**
+ * Create a GraphQL query and return the Request object
+ *
+ * @param string $name
+ * @param array $variables
+ * @return Request
+ */
+ public function queryRequest(string $name, array $variables = []): Request
+ {
+ $file = realpath("{$this->filePath}/Queries/{$name}.graphql");
+ if ($file === FALSE || ! file_exists($file))
+ {
+ throw new LogicException('GraphQL query file does not exist.');
+ }
+
+ $query = file_get_contents($file);
+ $body = [
+ 'query' => $query
+ ];
+
+ if ( ! empty($variables))
+ {
+ $body['variables'] = [];
+ foreach($variables as $key => $val)
+ {
+ $body['variables'][$key] = $val;
+ }
+ }
+
+ return $this->setUpRequest('POST', $this->baseUrl, [
+ 'body' => $body,
+ ]);
+ }
+
+ /**
+ * Create a GraphQL mutation request, and return the Request object
+ *
+ * @param string $name
+ * @param array $variables
+ * @return Request
+ */
+ public function mutateRequest (string $name, array $variables = []): Request
+ {
+ $file = realpath("{$this->filePath}/Mutations/{$name}.graphql");
+ if ($file === FALSE || ! file_exists($file))
+ {
+ throw new LogicException('GraphQL mutation file does not exist.');
+ }
+
+ $query = file_get_contents($file);
+ $body = [
+ 'query' => $query
+ ];
+
+ if (!empty($variables)) {
+ $body['variables'] = [];
+ foreach ($variables as $key => $val)
+ {
+ $body['variables'][$key] = $val;
+ }
+ }
+
+ return $this->setUpRequest('POST', $this->baseUrl, [
+ 'body' => $body,
+ ]);
+ }
+
/**
* Make a request
*
* @param string $type
* @param string $url
* @param array $options
- * @throws JsonException
- * @throws FailedResponseException
- * @throws Throwable
* @return array
*/
private function request(string $type, string $url, array $options = []): array
diff --git a/src/AnimeClient/API/Kitsu/Transformer/AnimeListTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/AnimeListTransformer.php
index bc2992d3..847efcf2 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/AnimeListTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/AnimeListTransformer.php
@@ -33,11 +33,12 @@ final class AnimeListTransformer extends AbstractTransformer {
* Convert raw api response to a more
* logical and workable structure
*
- * @param array $item API library item
+ * @param array|object $item API library item
* @return AnimeListItem
*/
- public function transform($item): AnimeListItem
+ public function transform(array|object $item): AnimeListItem
{
+ $item = (array)$item;
$animeId = $item['media']['id'];
$anime = $item['media'];
@@ -115,14 +116,13 @@ final class AnimeListTransformer extends AbstractTransformer {
* @param array $item Transformed library item
* @return FormItem API library item
*/
- public function untransform($item): FormItem
+ public function untransform(array $item): FormItem
{
$privacy = (array_key_exists('private', $item) && $item['private']);
$rewatching = (array_key_exists('rewatching', $item) && $item['rewatching']);
$untransformed = FormItem::from([
'id' => $item['id'],
- 'anilist_item_id' => $item['anilist_item_id'] ?? NULL,
'mal_id' => $item['mal_id'] ?? NULL,
'data' => [
'status' => $item['watching_status'],
diff --git a/src/AnimeClient/API/Kitsu/Transformer/AnimeTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/AnimeTransformer.php
index d98117e9..53c62e27 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/AnimeTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/AnimeTransformer.php
@@ -29,11 +29,12 @@ final class AnimeTransformer extends AbstractTransformer {
* Convert raw api response to a more
* logical and workable structure
*
- * @param array $item API library item
+ * @param array|object $item API library item
* @return AnimePage
*/
- public function transform($item): AnimePage
+ public function transform(array|object $item): AnimePage
{
+ $item = (array)$item;
$base = $item['data']['findAnimeBySlug'] ?? $item['data']['findAnimeById'] ?? $item['data']['randomMedia'];
$characters = [];
$links = [];
diff --git a/src/AnimeClient/API/Kitsu/Transformer/CharacterTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/CharacterTransformer.php
index 3cf43d6e..87cb5f9f 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/CharacterTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/CharacterTransformer.php
@@ -28,12 +28,13 @@ use Locale;
final class CharacterTransformer extends AbstractTransformer {
/**
- * @param array $characterData
+ * @param array|object $item
* @return Character
*/
- public function transform($characterData): Character
+ public function transform(array|object $item): Character
{
- $data = $characterData['data']['findCharacterBySlug'] ?? [];
+ $item = (array)$item;
+ $data = $item['data']['findCharacterBySlug'] ?? [];
$castings = [];
$media = [
'anime' => [],
diff --git a/src/AnimeClient/API/Kitsu/Transformer/HistoryTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/HistoryTransformer.php
index ad0974ac..1a37f9f0 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/HistoryTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/HistoryTransformer.php
@@ -65,7 +65,7 @@ abstract class HistoryTransformer {
foreach ($base as $entry)
{
- if ( ! (strtolower($entry['media']['__typename']) === $this->type))
+ if (strtolower($entry['media']['__typename']) !== $this->type)
{
continue;
}
@@ -210,7 +210,7 @@ abstract class HistoryTransformer {
]);
}
- protected function transformUpdated($entry): HistoryItem
+ protected function transformUpdated(array $entry): HistoryItem
{
$id = $entry['media']['id'];
$data = $entry['media'];
@@ -242,7 +242,7 @@ abstract class HistoryTransformer {
]);
}
- return $entry;
+ return HistoryItem::from($entry);
}
protected function linkTitle (array $data): string
@@ -257,6 +257,11 @@ abstract class HistoryTransformer {
$date
);
+ if ($dateTime === FALSE)
+ {
+ return new DateTimeImmutable();
+ }
+
return $dateTime->setTimezone(new DateTimeZone(date_default_timezone_get()));
}
@@ -265,7 +270,7 @@ abstract class HistoryTransformer {
return "/{$this->type}/details/{$data['slug']}";
}
- protected function isReconsuming ($entry): bool
+ protected function isReconsuming (array $entry): bool
{
return $entry['libraryEntry']['reconsuming'];
}
diff --git a/src/AnimeClient/API/Kitsu/Transformer/LibraryEntryTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/LibraryEntryTransformer.php
index b18409bd..5a5212e8 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/LibraryEntryTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/LibraryEntryTransformer.php
@@ -26,8 +26,9 @@ use Aviat\Ion\Type\StringType;
*/
final class LibraryEntryTransformer extends AbstractTransformer
{
- public function transform($item)
+ public function transform(array|object $item): AnimeListItem|MangaListItem
{
+ $item = (array)$item;
$type = $item['media']['type'] ?? '';
$genres = [];
@@ -37,20 +38,15 @@ final class LibraryEntryTransformer extends AbstractTransformer
sort($genres);
}
- switch (strtolower($type))
+ return match (strtolower($type))
{
- case 'anime':
- return $this->animeTransform($item, $genres);
-
- case 'manga':
- return $this->mangaTransform($item, $genres);
-
- default:
- return [];
- }
+ 'anime' => $this->animeTransform($item, $genres),
+ 'manga' => $this->mangaTransform($item, $genres),
+ default => AnimeListItem::from([]),
+ };
}
- private function animeTransform($item, array $genres): AnimeListItem
+ private function animeTransform(array $item, array $genres): AnimeListItem
{
$animeId = $item['media']['id'];
$anime = $item['media'];
@@ -119,7 +115,7 @@ final class LibraryEntryTransformer extends AbstractTransformer
]);
}
- private function mangaTransform($item, array $genres): MangaListItem
+ private function mangaTransform(array $item, array $genres): MangaListItem
{
$mangaId = $item['media']['id'];
$manga = $item['media'];
diff --git a/src/AnimeClient/API/Kitsu/Transformer/MangaListTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/MangaListTransformer.php
index 929f75bc..c8f97ba5 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/MangaListTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/MangaListTransformer.php
@@ -31,11 +31,12 @@ final class MangaListTransformer extends AbstractTransformer {
/**
* Remap zipped anime data to a more logical form
*
- * @param array $item manga entry item
+ * @param array|object $item manga entry item
* @return MangaListItem
*/
- public function transform($item): MangaListItem
+ public function transform(array|object $item): MangaListItem
{
+ $item = (array)$item;
$mangaId = $item['media']['id'];
$manga = $item['media'];
diff --git a/src/AnimeClient/API/Kitsu/Transformer/MangaTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/MangaTransformer.php
index 18041491..7c01a4d6 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/MangaTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/MangaTransformer.php
@@ -29,11 +29,12 @@ final class MangaTransformer extends AbstractTransformer {
* Convert raw api response to a more
* logical and workable structure
*
- * @param array $item API library item
+ * @param array|object $item API library item
* @return MangaPage
*/
- public function transform($item): MangaPage
+ public function transform(array|object $item): MangaPage
{
+ $item = (array)$item;
$base = $item['data']['findMangaBySlug'] ?? $item['data']['findMangaById'] ?? $item['data']['randomMedia'];
$characters = [];
$links = [];
diff --git a/src/AnimeClient/API/Kitsu/Transformer/PersonTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/PersonTransformer.php
index 9d6752bb..16d235ab 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/PersonTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/PersonTransformer.php
@@ -26,12 +26,13 @@ use Aviat\Ion\Transformer\AbstractTransformer;
final class PersonTransformer extends AbstractTransformer {
/**
- * @param array|object $personData
+ * @param array|object $item
* @return Person
*/
- public function transform($personData): Person
+ public function transform(array|object $item): Person
{
- $data = $personData['data']['findPersonBySlug'] ?? [];
+ $item = (array)$item;
+ $data = $item['data']['findPersonBySlug'] ?? [];
$canonicalName = $data['names']['localized'][$data['names']['canonical']]
?? array_shift($data['names']['localized']);
diff --git a/src/AnimeClient/API/Kitsu/Transformer/UserTransformer.php b/src/AnimeClient/API/Kitsu/Transformer/UserTransformer.php
index 00764cbb..236779f6 100644
--- a/src/AnimeClient/API/Kitsu/Transformer/UserTransformer.php
+++ b/src/AnimeClient/API/Kitsu/Transformer/UserTransformer.php
@@ -29,9 +29,10 @@ use Aviat\Ion\Transformer\AbstractTransformer;
* @return User
*/
final class UserTransformer extends AbstractTransformer {
- public function transform($profileData): User
+ public function transform(array|object $item): User
{
- $base = $profileData['data']['findProfileBySlug'] ?? [];
+ $item = (array)$item;
+ $base = $item['data']['findProfileBySlug'] ?? [];
$favorites = $base['favorites']['nodes'] ?? [];
$stats = $base['stats'] ?? [];
$waifu = (array_key_exists('waifu', $base)) ? [
@@ -71,7 +72,7 @@ final class UserTransformer extends AbstractTransformer {
return $output;
}
- private function organizeStats(array $stats, $data = []): array
+ private function organizeStats(array $stats, array $data = []): array
{
$animeStats = [];
$mangaStats = [];
diff --git a/src/AnimeClient/AnimeClient.php b/src/AnimeClient/AnimeClient.php
index 1b3d42b7..1a903d89 100644
--- a/src/AnimeClient/AnimeClient.php
+++ b/src/AnimeClient/AnimeClient.php
@@ -48,6 +48,11 @@ function loadConfig(string $path): array
$output = [];
$files = glob("{$path}/*.toml");
+ if ( ! is_array($files))
+ {
+ return [];
+ }
+
foreach ($files as $file)
{
$key = str_replace('.toml', '', basename($file));
@@ -86,7 +91,7 @@ function loadTomlFile(string $filename): array
return Toml::parseFile($filename);
}
-function _iterateToml(TomlBuilder $builder, iterable $data, $parentKey = NULL): void
+function _iterateToml(TomlBuilder $builder, iterable $data, mixed $parentKey = NULL): void
{
foreach ($data as $key => $value)
{
@@ -119,7 +124,7 @@ function _iterateToml(TomlBuilder $builder, iterable $data, $parentKey = NULL):
/**
* Serialize config data into a Toml file
*
- * @param mixed $data
+ * @param iterable $data
* @return string
*/
function arrayToToml(iterable $data): string
@@ -152,7 +157,7 @@ function tomlToArray(string $toml): array
* @param mixed $array
* @return bool
*/
-function isSequentialArray($array): bool
+function isSequentialArray(mixed $array): bool
{
if ( ! is_array($array))
{
@@ -265,7 +270,7 @@ function getLocalImg (string $kitsuUrl, $webp = TRUE): string
$parts = parse_url($kitsuUrl);
- if ($parts === FALSE)
+ if ($parts === FALSE || ! array_key_exists('path', $parts))
{
return 'images/placeholder.webp';
}
@@ -291,22 +296,35 @@ function getLocalImg (string $kitsuUrl, $webp = TRUE): string
* @param int|null $width
* @param int|null $height
* @param string $text
+ * @return bool
*/
-function createPlaceholderImage (string $path, ?int $width, ?int $height, $text = 'Image Unavailable'): void
+function createPlaceholderImage (string $path, ?int $width, ?int $height, $text = 'Image Unavailable'): bool
{
$width = $width ?? 200;
$height = $height ?? 200;
$img = imagecreatetruecolor($width, $height);
+ if ($img === FALSE)
+ {
+ return FALSE;
+ }
imagealphablending($img, TRUE);
$path = rtrim($path, '/');
// Background is the first color by default
$fillColor = imagecolorallocatealpha($img, 255, 255, 255, 127);
+ if ($fillColor === FALSE)
+ {
+ return FALSE;
+ }
imagefill($img, 0, 0, $fillColor);
$textColor = imagecolorallocate($img, 64, 64, 64);
+ if ($textColor === FALSE)
+ {
+ return FALSE;
+ }
imagealphablending($img, TRUE);
@@ -328,12 +346,18 @@ function createPlaceholderImage (string $path, ?int $width, ?int $height, $text
imagedestroy($img);
$pngImage = imagecreatefrompng($path . '/placeholder.png');
+ if ($pngImage === FALSE)
+ {
+ return FALSE;
+ }
imagealphablending($pngImage, TRUE);
imagesavealpha($pngImage, TRUE);
imagewebp($pngImage, $path . '/placeholder.webp');
imagedestroy($pngImage);
+
+ return TRUE;
}
/**
@@ -354,7 +378,7 @@ function colNotEmpty(array $search, string $key): bool
*
* @param CacheInterface $cache
* @return bool
- * @throws InvalidArgumentException
+ * @throws Throwable
*/
function clearCache(CacheInterface $cache): bool
{
@@ -389,5 +413,6 @@ function renderTemplate(string $path, array $data): string
ob_start();
extract($data, EXTR_OVERWRITE);
include $path;
- return ob_get_clean();
+ $rawOutput = ob_get_clean();
+ return (is_string($rawOutput)) ? $rawOutput : '';
}
\ No newline at end of file
diff --git a/src/AnimeClient/Command/BaseCommand.php b/src/AnimeClient/Command/BaseCommand.php
index f043d9e2..f05d2a60 100644
--- a/src/AnimeClient/Command/BaseCommand.php
+++ b/src/AnimeClient/Command/BaseCommand.php
@@ -52,13 +52,22 @@ abstract class BaseCommand extends Command {
* @param string|int|null $bgColor
* @return void
*/
- public function echoBox($message, $fgColor = NULL, $bgColor = NULL): void
+ public function echoBox(string|array $message, string|int|null $fgColor = NULL, string|int|null $bgColor = NULL): void
{
if (is_array($message))
{
$message = implode("\n", $message);
}
+ if ($fgColor !== NULL)
+ {
+ $fgColor = (string)$fgColor;
+ }
+ if ($bgColor !== NULL)
+ {
+ $bgColor = (string)$bgColor;
+ }
+
// color message
$message = Colors::colorize($message, $fgColor, $bgColor);
@@ -129,8 +138,17 @@ abstract class BaseCommand extends Command {
return $this->_di($configArray, $APP_DIR);
}
- private function _line(string $message, $fgColor = NULL, $bgColor = NULL): void
+ private function _line(string $message, int|string|null $fgColor = NULL, int|string|null $bgColor = NULL): void
{
+ if ($fgColor !== NULL)
+ {
+ $fgColor = (string)$fgColor;
+ }
+ if ($bgColor !== NULL)
+ {
+ $bgColor = (string)$bgColor;
+ }
+
$message = Colors::colorize($message, $fgColor, $bgColor);
$this->getConsole()->writeln($message);
}
diff --git a/src/AnimeClient/Command/SyncLists.php b/src/AnimeClient/Command/SyncLists.php
index 8eb01e0f..427ec829 100644
--- a/src/AnimeClient/Command/SyncLists.php
+++ b/src/AnimeClient/Command/SyncLists.php
@@ -218,7 +218,7 @@ final class SyncLists extends BaseCommand {
* @param array $data
* @throws Throwable
*/
- protected function update(string $type, array $data)
+ protected function update(string $type, array $data): void
{
if ( ! empty($data['addToAnilist']))
{
@@ -259,7 +259,7 @@ final class SyncLists extends BaseCommand {
// ------------------------------------------------------------------------
// Fetch helpers
// ------------------------------------------------------------------------
- private function fetchAnilistCount(string $type)
+ private function fetchAnilistCount(string $type): int
{
$list = $this->fetchAnilist($type);
diff --git a/src/AnimeClient/Controller.php b/src/AnimeClient/Controller.php
index c0827ee4..3f6a1cc3 100644
--- a/src/AnimeClient/Controller.php
+++ b/src/AnimeClient/Controller.php
@@ -203,7 +203,7 @@ class Controller {
* @throws NotFoundException
* @return string
*/
- protected function loadPartial($view, string $template, array $data = []): string
+ protected function loadPartial(HtmlView $view, string $template, array $data = []): string
{
$router = $this->container->get('dispatcher');
@@ -236,7 +236,7 @@ class Controller {
* @throws ContainerException
* @throws NotFoundException
*/
- protected function renderFullPage($view, string $template, array $data): HtmlView
+ protected function renderFullPage(HtmlView $view, string $template, array $data): HtmlView
{
$csp = [
"default-src 'self'",
@@ -360,7 +360,7 @@ class Controller {
* @throws NotFoundException
* @return string
*/
- protected function showMessage($view, string $type, string $message): string
+ protected function showMessage(HtmlView $view, string $type, string $message): string
{
return $this->loadPartial($view, 'message', [
'message_type' => $type,
@@ -399,7 +399,7 @@ class Controller {
* @throws DoubleRenderException
* @return void
*/
- protected function outputJSON($data, int $code): void
+ protected function outputJSON(mixed $data, int $code): void
{
(new JsonView())
->setOutput($data)
@@ -420,10 +420,7 @@ class Controller {
{
(new HttpView())->redirect($url, $code)->send();
}
- catch (\Throwable $e)
- {
-
- }
+ catch (\Throwable) {}
}
}
// End of BaseController.php
\ No newline at end of file
diff --git a/src/AnimeClient/Controller/Anime.php b/src/AnimeClient/Controller/Anime.php
index 04bd7862..e011e426 100644
--- a/src/AnimeClient/Controller/Anime.php
+++ b/src/AnimeClient/Controller/Anime.php
@@ -145,7 +145,7 @@ final class Anime extends BaseController {
{
$this->checkAuth();
- $data = $this->request->getParsedBody();
+ $data = (array)$this->request->getParsedBody();
if (empty($data['mal_id']))
{
@@ -220,7 +220,7 @@ final class Anime extends BaseController {
{
$this->checkAuth();
- $data = $this->request->getParsedBody();
+ $data = (array)$this->request->getParsedBody();
// Do some minor data manipulation for
// large form-based updates
@@ -257,7 +257,7 @@ final class Anime extends BaseController {
}
else
{
- $data = $this->request->getParsedBody();
+ $data = (array)$this->request->getParsedBody();
}
if (empty($data))
@@ -282,7 +282,7 @@ final class Anime extends BaseController {
{
$this->checkAuth();
- $body = $this->request->getParsedBody();
+ $body = (array)$this->request->getParsedBody();
$response = $this->model->deleteLibraryItem($body['id'], $body['mal_id']);
if ($response === TRUE)
diff --git a/src/AnimeClient/Controller/AnimeCollection.php b/src/AnimeClient/Controller/AnimeCollection.php
index 0935d181..97de11d4 100644
--- a/src/AnimeClient/Controller/AnimeCollection.php
+++ b/src/AnimeClient/Controller/AnimeCollection.php
@@ -154,7 +154,7 @@ final class AnimeCollection extends BaseController {
public function edit(): void
{
$this->checkAuth();
- $this->update($this->request->getParsedBody());
+ $this->update((array)$this->request->getParsedBody());
}
/**
@@ -169,7 +169,7 @@ final class AnimeCollection extends BaseController {
{
$this->checkAuth();
- $data = $this->request->getParsedBody();
+ $data = (array)$this->request->getParsedBody();
if (array_key_exists('id', $data))
{
// Check for existing entry
@@ -218,7 +218,7 @@ final class AnimeCollection extends BaseController {
{
$this->checkAuth();
- $data = $this->request->getParsedBody();
+ $data = (array)$this->request->getParsedBody();
if ( ! array_key_exists('hummingbird_id', $data))
{
$this->setFlashMessage("Can't delete item that doesn't exist", 'error');
@@ -238,11 +238,11 @@ final class AnimeCollection extends BaseController {
/**
* Update a collection item
*
- * @param $data
+ * @param array $data
* @throws ContainerException
* @throws NotFoundException
*/
- protected function update($data): void
+ protected function update(array $data): void
{
if (array_key_exists('hummingbird_id', $data))
{
diff --git a/src/AnimeClient/Controller/Images.php b/src/AnimeClient/Controller/Images.php
index dbceec27..1f526d7a 100644
--- a/src/AnimeClient/Controller/Images.php
+++ b/src/AnimeClient/Controller/Images.php
@@ -37,9 +37,7 @@ final class Images extends BaseController {
* @param string $file The filename to look for
* @param bool $display Whether to output the image to the server
* @return void
- * @throws NotFoundException
* @throws Throwable
- * @throws ContainerException
*/
public function cache(string $type, string $file, $display = TRUE): void
{
@@ -134,7 +132,16 @@ final class Images extends BaseController {
[$origWidth] = getimagesizefromstring($data);
$gdImg = imagecreatefromstring($data);
+ if ($gdImg === FALSE)
+ {
+ return;
+ }
+
$resizedImg = imagescale($gdImg, $width ?? $origWidth);
+ if ($resizedImg === FALSE)
+ {
+ return;
+ }
if ($ext === 'gif')
{
@@ -161,7 +168,7 @@ final class Images extends BaseController {
? 'image/webp'
: $response->getHeader('content-type')[0];
- $outputFile = (strpos($file, '-original') !== FALSE)
+ $outputFile = (str_contains($file, '-original'))
? "{$filePrefix}-original.{$ext}"
: "{$filePrefix}.{$ext}";
diff --git a/src/AnimeClient/Controller/Manga.php b/src/AnimeClient/Controller/Manga.php
index fd26aded..049be5a1 100644
--- a/src/AnimeClient/Controller/Manga.php
+++ b/src/AnimeClient/Controller/Manga.php
@@ -135,15 +135,13 @@ final class Manga extends Controller {
* Add an manga to the list
*
* @return void
- * @throws NotFoundException
* @throws Throwable
- * @throws ContainerException
*/
public function add(): void
{
$this->checkAuth();
- $data = $this->request->getParsedBody();
+ $data = (array)$this->request->getParsedBody();
if ( ! array_key_exists('id', $data))
{
$this->redirect('manga/add', 303);
@@ -163,7 +161,7 @@ final class Manga extends Controller {
}
else
{
- $this->setFlashMessage('Failed to add new manga to list' . $result['body'], 'error');
+ $this->setFlashMessage('Failed to add new manga to list:' . print_r($data, TRUE), 'error');
}
$this->sessionRedirect();
@@ -180,7 +178,7 @@ final class Manga extends Controller {
* @throws InvalidArgumentException
* @return void
*/
- public function edit($id, $status = 'All'): void
+ public function edit(string $id, string $status = 'All'): void
{
$this->checkAuth();
@@ -218,14 +216,12 @@ final class Manga extends Controller {
*
* @return void
* @throws Throwable
- * @throws NotFoundException
- * @throws ContainerException
*/
public function formUpdate(): void
{
$this->checkAuth();
- $data = $this->request->getParsedBody();
+ $data = (array)$this->request->getParsedBody();
// Do some minor data manipulation for
// large form-based updates
@@ -275,8 +271,6 @@ final class Manga extends Controller {
/**
* Remove an manga from the list
*
- * @throws ContainerException
- * @throws NotFoundException
* @throws Throwable
* @return void
*/
@@ -284,7 +278,7 @@ final class Manga extends Controller {
{
$this->checkAuth();
- $body = $this->request->getParsedBody();
+ $body = (array)$this->request->getParsedBody();
$response = $this->model->deleteLibraryItem($body['id'], $body['mal_id']);
if ($response)
diff --git a/src/AnimeClient/Controller/Misc.php b/src/AnimeClient/Controller/Misc.php
index 208bb29a..6d4a72b7 100644
--- a/src/AnimeClient/Controller/Misc.php
+++ b/src/AnimeClient/Controller/Misc.php
@@ -74,7 +74,7 @@ final class Misc extends BaseController {
*/
public function loginAction(): void
{
- $post = $this->request->getParsedBody();
+ $post = (array)$this->request->getParsedBody();
if ($this->auth->authenticate($post['password']))
{
@@ -83,7 +83,11 @@ final class Misc extends BaseController {
}
$this->setFlashMessage('Invalid username or password.');
- $this->redirect($this->url->generate('login'), 303);
+
+ $redirectUrl = $this->url->generate('login');
+ $redirectUrl = ($redirectUrl !== FALSE) ? $redirectUrl : '';
+
+ $this->redirect($redirectUrl, 303);
}
/**
diff --git a/src/AnimeClient/Controller/Settings.php b/src/AnimeClient/Controller/Settings.php
index c564e9db..2e78e9f5 100644
--- a/src/AnimeClient/Controller/Settings.php
+++ b/src/AnimeClient/Controller/Settings.php
@@ -84,7 +84,7 @@ final class Settings extends BaseController {
*/
public function update(): void
{
- $post = $this->request->getParsedBody();
+ $post = (array)$this->request->getParsedBody();
unset($post['settings-tabs']);
$saved = $this->settingsModel->saveSettingsFile($post);
@@ -93,7 +93,10 @@ final class Settings extends BaseController {
? $this->setFlashMessage('Saved config settings.', 'success')
: $this->setFlashMessage('Failed to save config file.', 'error');
- $this->redirect($this->url->generate('settings'), 303);
+ $redirectUrl = $this->url->generate('settings');
+ $redirectUrl = ($redirectUrl !== FALSE) ? $redirectUrl : '';
+
+ $this->redirect($redirectUrl, 303);
}
/**
@@ -152,6 +155,9 @@ final class Settings extends BaseController {
? $this->setFlashMessage('Linked Anilist Account', 'success')
: $this->setFlashMessage('Error Linking Anilist Account', 'error');
- $this->redirect($this->url->generate('settings'), 303);
+ $redirectUrl = $this->url->generate('settings');
+ $redirectUrl = ($redirectUrl !== FALSE) ? $redirectUrl : '';
+
+ $this->redirect($redirectUrl, 303);
}
}
\ No newline at end of file
diff --git a/src/AnimeClient/Dispatcher.php b/src/AnimeClient/Dispatcher.php
index 6a6d53f3..0be584fb 100644
--- a/src/AnimeClient/Dispatcher.php
+++ b/src/AnimeClient/Dispatcher.php
@@ -16,19 +16,23 @@
namespace Aviat\AnimeClient;
-use Aviat\AnimeClient\Enum\EventType;
-use function Aviat\Ion\_dir;
-
-use Aura\Router\{Map, Matcher, Route, Rule};
-
+use Aviat\Ion\Json;
+use Aura\Router\{
+ Map,
+ Matcher,
+ Route,
+ Rule,
+};
use Aviat\AnimeClient\API\FailedResponseException;
use Aviat\Ion\Di\ContainerInterface;
-use Aviat\Ion\Event;
use Aviat\Ion\Friend;
use Aviat\Ion\Type\StringType;
+use JetBrains\PhpStorm\ArrayShape;
use LogicException;
use ReflectionException;
+use function Aviat\Ion\_dir;
+
/**
* Basic routing/ dispatch
*/
@@ -78,7 +82,7 @@ final class Dispatcher extends RoutingBase {
*
* @return Route|false
*/
- public function getRoute()
+ public function getRoute(): Route | false
{
$logger = $this->container->getLogger();
@@ -132,7 +136,7 @@ final class Dispatcher extends RoutingBase {
{
// If not route was matched, return an appropriate http
// error message
- $errorRoute = $this->getErrorParams();
+ $errorRoute = (array)$this->getErrorParams();
$controllerName = DEFAULT_CONTROLLER;
$actionMethod = $errorRoute['action_method'];
$params = $errorRoute['params'];
@@ -152,11 +156,11 @@ final class Dispatcher extends RoutingBase {
* Parse out the arguments for the appropriate controller for
* the current route
*
- * @param Route $route
+ * @param Friend $route
* @throws LogicException
* @return array
*/
- protected function processRoute($route): array
+ protected function processRoute(Friend $route): array
{
if ( ! array_key_exists('controller', $route->attributes))
{
@@ -166,7 +170,7 @@ final class Dispatcher extends RoutingBase {
$controllerName = $route->attributes['controller'];
// Get the full namespace for a controller if a short name is given
- if (strpos($controllerName, '\\') === FALSE)
+ if ( ! str_contains($controllerName, '\\'))
{
$map = $this->getControllerList();
$controllerName = $map[$controllerName];
@@ -191,7 +195,7 @@ final class Dispatcher extends RoutingBase {
$logger = $this->container->getLogger();
if ($logger !== NULL)
{
- $logger->info(json_encode($params));
+ $logger->info(Json::encode($params));
}
return [
@@ -244,6 +248,10 @@ final class Dispatcher extends RoutingBase {
$path = trim($path, '/');
$actualPath = realpath(_dir(SRC_DIR, $path));
$classFiles = glob("{$actualPath}/*.php");
+ if ($classFiles === FALSE)
+ {
+ return [];
+ }
$controllers = [];
@@ -282,9 +290,10 @@ final class Dispatcher extends RoutingBase {
$logger->debug('Dispatcher - controller arguments', $params);
}
- call_user_func_array([$controller, $method], array_values($params));
+ $params = array_values($params);
+ $controller->$method(...$params);
}
- catch (FailedResponseException $e)
+ catch (FailedResponseException)
{
$controllerName = DEFAULT_CONTROLLER;
$controller = new $controllerName($this->container);
diff --git a/src/AnimeClient/FormGenerator.php b/src/AnimeClient/FormGenerator.php
index c0a50ce3..a659e119 100644
--- a/src/AnimeClient/FormGenerator.php
+++ b/src/AnimeClient/FormGenerator.php
@@ -48,7 +48,7 @@ final class FormGenerator {
* Create a new FormGenerator
*
* @param ContainerInterface $container
- * @return $this
+ * @return self
*/
public static function new(ContainerInterface $container): self
{
diff --git a/src/AnimeClient/Kitsu.php b/src/AnimeClient/Kitsu.php
index f4162dc2..ddd3c717 100644
--- a/src/AnimeClient/Kitsu.php
+++ b/src/AnimeClient/Kitsu.php
@@ -166,7 +166,7 @@ final class Kitsu {
*/
public static function parseStreamingLinks(array $nodes): array
{
- if (count($nodes) === 0)
+ if (empty($nodes))
{
return [];
}
@@ -179,12 +179,16 @@ final class Kitsu {
// 'Fix' links that start with the hostname,
// rather than a protocol
- if (strpos($url, '//') === FALSE)
+ if ( ! str_contains($url, '//'))
{
$url = '//' . $url;
}
$host = parse_url($url, \PHP_URL_HOST);
+ if ($host === FALSE)
+ {
+ return [];
+ }
$links[] = [
'meta' => self::getServiceMetaData($host),
@@ -401,7 +405,7 @@ final class Kitsu {
if (empty($parts))
{
- return $last;
+ return ($last !== NULL) ? $last : '';
}
return (count($parts) > 1)
@@ -412,11 +416,11 @@ final class Kitsu {
/**
* Determine if an alternate title is unique enough to list
*
- * @param string $title
+ * @param string|null $title
* @param array $existingTitles
* @return bool
*/
- private static function titleIsUnique(string $title = '', array $existingTitles = []): bool
+ protected static function titleIsUnique(?string $title = '', array $existingTitles = []): bool
{
if (empty($title))
{
diff --git a/src/AnimeClient/MenuGenerator.php b/src/AnimeClient/MenuGenerator.php
index 3951dacc..98e27f72 100644
--- a/src/AnimeClient/MenuGenerator.php
+++ b/src/AnimeClient/MenuGenerator.php
@@ -22,7 +22,7 @@ use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Exception\ConfigException;
use Aviat\Ion\Type\ArrayType;
use Aviat\Ion\Type\StringType;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
/**
* Helper object to manage menu creation and selection
@@ -39,13 +39,13 @@ final class MenuGenerator extends UrlGenerator {
/**
* Request object
*
- * @var RequestInterface
+ * @var ServerRequestInterface
*/
- protected RequestInterface $request;
+ protected ServerRequestInterface $request;
/**
* @param ContainerInterface $container
- * @return static
+ * @return self
*/
public static function new(ContainerInterface $container): self
{
diff --git a/src/AnimeClient/Model/AnimeCollection.php b/src/AnimeClient/Model/AnimeCollection.php
index 74301911..6802d0d8 100644
--- a/src/AnimeClient/Model/AnimeCollection.php
+++ b/src/AnimeClient/Model/AnimeCollection.php
@@ -50,6 +50,11 @@ final class AnimeCollection extends Collection {
*/
public function getCollection(): array
{
+ if ($this->db === NULL)
+ {
+ return [];
+ }
+
$rawCollection = $this->getCollectionFromDatabase();
$collection = [];
@@ -76,7 +81,7 @@ final class AnimeCollection extends Collection {
*/
public function getFlatCollection(): array
{
- if ( ! $this->validDatabase)
+ if ($this->db === NULL)
{
return [];
}
@@ -92,6 +97,11 @@ final class AnimeCollection extends Collection {
$genres = $this->getGenreList();
$media = $this->getMediaList();
+ if ($rows === FALSE)
+ {
+ return [];
+ }
+
foreach($rows as &$row)
{
$id = $row['hummingbird_id'];
@@ -117,7 +127,7 @@ final class AnimeCollection extends Collection {
*/
public function getMediaTypeList(): array
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return [];
}
@@ -128,7 +138,13 @@ final class AnimeCollection extends Collection {
->from('media')
->get();
- foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row)
+ $rows = $query->fetchAll(PDO::FETCH_ASSOC);
+ if ($rows === FALSE)
+ {
+ return [];
+ }
+
+ foreach ($rows as $row)
{
$flatList[$row['id']] = $row['type'];
}
@@ -158,12 +174,12 @@ final class AnimeCollection extends Collection {
/**
* Add an item to the anime collection
*
- * @param array $data
+ * @param mixed $data
* @return void
*/
- public function add($data): void
+ public function add(mixed $data): void
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return;
}
@@ -197,12 +213,12 @@ final class AnimeCollection extends Collection {
/**
* Verify that an item was added
*
- * @param array|null|object $data
+ * @param array $data
* @return bool
*/
- public function wasAdded($data): bool
+ public function wasAdded(array $data): bool
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return FALSE;
}
@@ -218,9 +234,9 @@ final class AnimeCollection extends Collection {
* @param array $data
* @return void
*/
- public function update($data): void
+ public function update(array $data): void
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return;
}
@@ -253,13 +269,13 @@ final class AnimeCollection extends Collection {
/**
* Verify that the collection item was updated
*
- * @param array|null|object $data
+ * @param array $data
*
* @return bool
*/
- public function wasUpdated($data): bool
+ public function wasUpdated(array $data): bool
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return FALSE;
}
@@ -288,9 +304,9 @@ final class AnimeCollection extends Collection {
* @param array $data
* @return void
*/
- public function delete($data): void
+ public function delete(array $data): void
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return;
}
@@ -316,12 +332,12 @@ final class AnimeCollection extends Collection {
}
/**
- * @param array|null|object $data
+ * @param array $data
* @return bool
*/
- public function wasDeleted($data): bool
+ public function wasDeleted(array $data): bool
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return FALSE;
}
@@ -335,9 +351,9 @@ final class AnimeCollection extends Collection {
* @param int|string $kitsuId
* @return array
*/
- public function get($kitsuId): array
+ public function get(int|string $kitsuId): array
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return [];
}
@@ -348,6 +364,11 @@ final class AnimeCollection extends Collection {
->get()
->fetch(PDO::FETCH_ASSOC);
+ if ($row === FALSE)
+ {
+ return [];
+ }
+
// Get the media ids
$mediaRows = $this->db->select('media_id')
->from('anime_set_media_link')
@@ -355,6 +376,11 @@ final class AnimeCollection extends Collection {
->get()
->fetchAll(PDO::FETCH_ASSOC);
+ if ($mediaRows === FALSE)
+ {
+ return [];
+ }
+
$row['media_id'] = array_column($mediaRows, 'media_id');
return $row;
@@ -366,9 +392,9 @@ final class AnimeCollection extends Collection {
* @param int|string $kitsuId
* @return bool
*/
- public function has($kitsuId): bool
+ public function has(int|string $kitsuId): bool
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return FALSE;
}
@@ -390,7 +416,7 @@ final class AnimeCollection extends Collection {
*/
public function getGenreList(array $filter = []): array
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return [];
}
@@ -416,7 +442,13 @@ final class AnimeCollection extends Collection {
->orderBy('genre')
->get();
- foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row)
+ $rows = $query->fetchAll(PDO::FETCH_ASSOC);
+ if ($rows === FALSE)
+ {
+ return [];
+ }
+
+ foreach ($rows as $row)
{
$id = $row['hummingbird_id'];
$genre = $row['genre'];
@@ -437,7 +469,7 @@ final class AnimeCollection extends Collection {
}
}
}
- catch (PDOException $e) {}
+ catch (PDOException) {}
$this->db->resetQuery();
@@ -452,7 +484,7 @@ final class AnimeCollection extends Collection {
*/
public function getMediaList(array $filter = []): array
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return [];
}
@@ -478,7 +510,13 @@ final class AnimeCollection extends Collection {
->orderBy('media')
->get();
- foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row)
+ $rows = $query->fetchAll(PDO::FETCH_ASSOC);
+ if ($rows === FALSE)
+ {
+ return [];
+ }
+
+ foreach ($rows as $row)
{
$id = $row['hummingbird_id'];
$media = $row['media'];
@@ -508,6 +546,11 @@ final class AnimeCollection extends Collection {
private function updateMediaLink(string $animeId, array $media): void
{
+ if ($this->db === NULL)
+ {
+ return;
+ }
+
$this->db->beginTransaction();
// Delete the old entries
@@ -537,7 +580,7 @@ final class AnimeCollection extends Collection {
*/
private function updateGenres($animeId): void
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return;
}
@@ -571,13 +614,13 @@ final class AnimeCollection extends Collection {
}
}
- if ( ! empty($linksToInsert))
+ if ($this->db !== NULL && ! empty($linksToInsert))
{
try
{
$this->db->insertBatch('anime_set_genre_link', $linksToInsert);
}
- catch (PDOException $e) {}
+ catch (PDOException) {}
}
}
@@ -588,7 +631,7 @@ final class AnimeCollection extends Collection {
*/
private function addNewGenres(array $genres): void
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return;
}
@@ -609,7 +652,7 @@ final class AnimeCollection extends Collection {
{
$this->db->insertBatch('genres', $insert);
}
- catch (PDOException $e)
+ catch (PDOException)
{
// dump($e);
}
@@ -630,7 +673,7 @@ final class AnimeCollection extends Collection {
private function getExistingGenres(): array
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return [];
}
@@ -642,7 +685,13 @@ final class AnimeCollection extends Collection {
->from('genres')
->get();
- foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $genre)
+ $rows = $query->fetchAll(PDO::FETCH_ASSOC);
+ if ($rows === FALSE)
+ {
+ return [];
+ }
+
+ foreach ($rows as $genre)
{
$genres[$genre['id']] = $genre['genre'];
}
@@ -654,7 +703,7 @@ final class AnimeCollection extends Collection {
private function getExistingGenreLinkEntries(): array
{
- if ($this->validDatabase === FALSE)
+ if ($this->db === NULL)
{
return [];
}
@@ -665,7 +714,13 @@ final class AnimeCollection extends Collection {
->from('anime_set_genre_link')
->get();
- foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $link)
+ $rows = $query->fetchAll(PDO::FETCH_ASSOC);
+ if ($rows === FALSE)
+ {
+ return [];
+ }
+
+ foreach ($rows as $link)
{
if (array_key_exists($link['hummingbird_id'], $links))
{
@@ -689,7 +744,7 @@ final class AnimeCollection extends Collection {
*/
private function getCollectionFromDatabase(): array
{
- if ( ! $this->validDatabase)
+ if ($this->db === NULL)
{
return [];
}
@@ -706,6 +761,11 @@ final class AnimeCollection extends Collection {
// Add genres associated with each item
$rows = $query->fetchAll(PDO::FETCH_ASSOC);
+ if ($rows === FALSE)
+ {
+ return [];
+ }
+
$genres = $this->getGenreList();
foreach($rows as &$row)
diff --git a/src/AnimeClient/Model/Collection.php b/src/AnimeClient/Model/Collection.php
index 9d0bcb59..d369af3f 100644
--- a/src/AnimeClient/Model/Collection.php
+++ b/src/AnimeClient/Model/Collection.php
@@ -29,15 +29,9 @@ class Collection extends DB {
/**
* The query builder object
- * @var QueryBuilderInterface
+ * @var QueryBuilderInterface|null
*/
- protected QueryBuilderInterface $db;
-
- /**
- * Whether the database is valid for querying
- * @var boolean
- */
- protected bool $validDatabase = FALSE;
+ protected ?QueryBuilderInterface $db;
/**
* Create a new collection object
@@ -51,9 +45,8 @@ class Collection extends DB {
try
{
$this->db = Query($this->dbConfig);
- $this->validDatabase = TRUE;
}
- catch (PDOException $e)
+ catch (PDOException)
{
$this->db = Query([
'type' => 'sqlite',
@@ -67,19 +60,12 @@ class Collection extends DB {
{
$dbFileName = $this->dbConfig['file'];
- if ($dbFileName !== ':memory:' && file_exists($dbFileName))
+ if ($dbFileName !== ':memory:')
{
- $dbFile = file_get_contents($dbFileName);
- $this->validDatabase = (strpos($dbFile, 'SQLite format 3') === 0);
+ $rawFile = file_get_contents($dbFileName);
+ $dbFile = ($rawFile !== FALSE) ? $rawFile : '';
+ $this->db = (str_starts_with($dbFile, 'SQLite format 3')) ? $this->db : NULL;
}
- else
- {
- $this->validDatabase = FALSE;
- }
- }
- else if ($this->db === NULL)
- {
- $this->validDatabase = FALSE;
}
}
}
diff --git a/src/AnimeClient/Model/MediaTrait.php b/src/AnimeClient/Model/MediaTrait.php
index aac8fabe..14e2535c 100644
--- a/src/AnimeClient/Model/MediaTrait.php
+++ b/src/AnimeClient/Model/MediaTrait.php
@@ -85,7 +85,7 @@ trait MediaTrait {
* @param string $itemId
* @return AnimeListItem|MangaListItem
*/
- public function getLibraryItem(string $itemId)
+ public function getLibraryItem(string $itemId): AnimeListItem|MangaListItem
{
return $this->kitsuModel->getListItem($itemId);
}
@@ -100,7 +100,13 @@ trait MediaTrait {
public function createLibraryItem(array $data): bool
{
$requester = new ParallelAPIRequest();
- $requester->addRequest($this->kitsuModel->createListItem($data), 'kitsu');
+ $kitsuRequest = $this->kitsuModel->createListItem($data);
+ if ($kitsuRequest === NULL)
+ {
+ return FALSE;
+ }
+
+ $requester->addRequest($kitsuRequest, 'kitsu');
if ($this->anilistEnabled && $data['mal_id'] !== null)
{
diff --git a/src/AnimeClient/Model/Settings.php b/src/AnimeClient/Model/Settings.php
index 7d413cf5..13bacb76 100644
--- a/src/AnimeClient/Model/Settings.php
+++ b/src/AnimeClient/Model/Settings.php
@@ -69,9 +69,7 @@ final class Settings {
{
$output = [];
- $settings = $this->getSettings();
-
- foreach($settings as $file => $values)
+ foreach($this->getSettings() as $file => $values)
{
$values = $values ?? [];
@@ -126,6 +124,10 @@ final class Settings {
public function validateSettings(array $settings): array
{
$cfg = Config::check($settings);
+ if ( ! is_iterable($cfg))
+ {
+ return [];
+ }
$looseConfig = [];
$keyedConfig = [];
diff --git a/src/AnimeClient/RoutingBase.php b/src/AnimeClient/RoutingBase.php
index 1d91fd6d..e4cd80f7 100644
--- a/src/AnimeClient/RoutingBase.php
+++ b/src/AnimeClient/RoutingBase.php
@@ -22,7 +22,7 @@ use Aviat\Ion\Di\Exception\ContainerException;
use Aviat\Ion\Di\Exception\NotFoundException;
use Aviat\Ion\Exception\ConfigException;
use Aviat\Ion\Type\StringType;
-use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ServerRequestInterface;
/**
* Base for routing/url classes
@@ -43,9 +43,9 @@ class RoutingBase {
/**
* Class wrapper for input superglobals
- * @var RequestInterface
+ * @var ServerRequestInterface
*/
- protected RequestInterface $request;
+ protected ServerRequestInterface $request;
/**
* Constructor
@@ -64,8 +64,7 @@ class RoutingBase {
/**
* Get the current url path
- * @throws ContainerException
- * @throws NotFoundException
+ *
* @return string
*/
public function path(): string
@@ -82,8 +81,7 @@ class RoutingBase {
/**
* Get the url segments
- * @throws ContainerException
- * @throws NotFoundException
+ *
* @return array
*/
public function segments(): array
@@ -96,11 +94,10 @@ class RoutingBase {
* Get a segment of the current url
*
* @param int $num
- * @throws ContainerException
- * @throws NotFoundException
+ *
* @return string|null
*/
- public function getSegment($num): ?string
+ public function getSegment(int $num): ?string
{
$segments = $this->segments();
return $segments[$num] ?? NULL;
@@ -109,8 +106,6 @@ class RoutingBase {
/**
* Retrieve the last url segment
*
- * @throws ContainerException
- * @throws NotFoundException
* @return string
*/
public function lastSegment(): string
diff --git a/src/AnimeClient/Types/AbstractType.php b/src/AnimeClient/Types/AbstractType.php
index 7a3b6407..32766d2e 100644
--- a/src/AnimeClient/Types/AbstractType.php
+++ b/src/AnimeClient/Types/AbstractType.php
@@ -23,10 +23,10 @@ abstract class AbstractType implements ArrayAccess, Countable {
/**
* Populate values for un-serializing data
*
- * @param $properties
+ * @param mixed $properties
* @return self
*/
- public static function __set_state($properties): self
+ public static function __set_state(mixed $properties): self
{
return new static($properties);
}
@@ -43,7 +43,7 @@ abstract class AbstractType implements ArrayAccess, Countable {
if (get_parent_class($currentClass) !== FALSE)
{
- return (new $currentClass($data))->toArray();
+ return static::class::from($data)->toArray();
}
return NULL;
@@ -55,7 +55,7 @@ abstract class AbstractType implements ArrayAccess, Countable {
* @param mixed $data
* @return static
*/
- final public static function from($data): self
+ final public static function from(mixed $data): static
{
return new static($data);
}
@@ -65,7 +65,7 @@ abstract class AbstractType implements ArrayAccess, Countable {
*
* @param mixed $data
*/
- final private function __construct($data = [])
+ final private function __construct(mixed $data = [])
{
$typeKeys = array_keys((array)$this);
$dataKeys = array_keys((array)$data);
@@ -87,10 +87,10 @@ abstract class AbstractType implements ArrayAccess, Countable {
/**
* See if a property is set
*
- * @param $name
+ * @param string $name
* @return bool
*/
- final public function __isset($name): bool
+ final public function __isset(string $name): bool
{
return property_exists($this, $name) && isset($this->$name);
}
@@ -102,7 +102,7 @@ abstract class AbstractType implements ArrayAccess, Countable {
* @param mixed $value
* @return void
*/
- final public function __set($name, $value): void
+ final public function __set(string $name, mixed $value): void
{
$setterMethod = 'set' . ucfirst($name);
@@ -128,7 +128,7 @@ abstract class AbstractType implements ArrayAccess, Countable {
* @param string $name
* @return mixed
*/
- final public function __get($name)
+ final public function __get(string $name): mixed
{
// Be a bit more lenient here, so that you can easily typecast missing
// values to reasonable defaults, and not have to resort to array indexes
@@ -148,46 +148,47 @@ abstract class AbstractType implements ArrayAccess, Countable {
/**
* Implementing ArrayAccess
*
- * @param $offset
+ * @param mixed $offset
* @return bool
*/
- final public function offsetExists($offset): bool
+ final public function offsetExists(mixed $offset): bool
{
- return $this->__isset($offset);
+ return $this->__isset((string)$offset);
}
/**
* Implementing ArrayAccess
*
- * @param $offset
+ * @param mixed $offset
* @return mixed
*/
- final public function offsetGet($offset)
+ final public function offsetGet(mixed $offset): mixed
{
- return $this->__get($offset);
+ return $this->__get((string)$offset);
}
/**
* Implementing ArrayAccess
*
- * @param $offset
- * @param $value
+ * @param mixed $offset
+ * @param mixed $value
*/
- final public function offsetSet($offset, $value): void
+ final public function offsetSet(mixed $offset, mixed $value): void
{
- $this->__set($offset, $value);
+ $this->__set((string)$offset, $value);
}
/**
* Implementing ArrayAccess
*
- * @param $offset
+ * @param mixed $offset
*/
- final public function offsetUnset($offset): void
+ final public function offsetUnset(mixed $offset): void
{
if ($this->offsetExists($offset))
{
- unset($this->$offset);
+ $strOffset = (string)$offset;
+ unset($this->$strOffset);
}
}
@@ -198,17 +199,44 @@ abstract class AbstractType implements ArrayAccess, Countable {
*/
final public function count(): int
{
- $keys = array_keys($this->toArray());
+ $keys = array_keys((array)$this->toArray());
return count($keys);
}
/**
* Recursively cast properties to an array
*
+ * Returns early on primitive values to work recursively.
+ *
* @param mixed $parent
- * @return mixed
+ * @return array
*/
- final public function toArray($parent = null)
+ final public function toArray(mixed $parent = null): array
+ {
+ $fromObject = $this->fromObject($parent);
+ return (is_array($fromObject)) ? $fromObject : [];
+ }
+
+ /**
+ * Determine whether the type has any properties set
+ *
+ * @return bool
+ */
+ final public function isEmpty(): bool
+ {
+ $self = (array)$this->toArray();
+ foreach ($self as $value)
+ {
+ if ( ! empty($value))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+
+ final protected function fromObject(mixed $parent = null): float|null|bool|int|array|string
{
$object = $parent ?? $this;
@@ -223,27 +251,9 @@ abstract class AbstractType implements ArrayAccess, Countable {
{
$output[$key] = (is_scalar($value) || empty($value))
? $value
- : $this->toArray((array) $value);
+ : $this->fromObject((array) $value);
}
return $output;
}
-
- /**
- * Determine whether the type has any properties set
- *
- * @return bool
- */
- final public function isEmpty(): bool
- {
- foreach ($this as $value)
- {
- if ( ! empty($value))
- {
- return FALSE;
- }
- }
-
- return TRUE;
- }
}
diff --git a/src/AnimeClient/Types/Anime.php b/src/AnimeClient/Types/Anime.php
index 357345a7..115be3c5 100644
--- a/src/AnimeClient/Types/Anime.php
+++ b/src/AnimeClient/Types/Anime.php
@@ -35,9 +35,9 @@ class Anime extends AbstractType {
public array $genres = [];
/**
- * @var string|int
+ * @var string
*/
- public $id = '';
+ public string $id = '';
public array $included = [];
diff --git a/src/AnimeClient/Types/AnimeListItem.php b/src/AnimeClient/Types/AnimeListItem.php
index 2a2c484f..56d41c2d 100644
--- a/src/AnimeClient/Types/AnimeListItem.php
+++ b/src/AnimeClient/Types/AnimeListItem.php
@@ -24,11 +24,6 @@ final class AnimeListItem extends AbstractType {
public ?string $mal_id;
- /**
- * @var string
- */
- public $anilist_item_id;
-
public array $episodes = [
'length' => 0,
'total' => 0,
@@ -54,14 +49,14 @@ final class AnimeListItem extends AbstractType {
/**
* @var string|int
*/
- public $user_rating = '';
+ public string|int $user_rating = '';
/**
* One of Aviat\AnimeClient\API\Enum\AnimeWatchingStatus
*/
public string $watching_status;
- public function setAnime($anime): void
+ public function setAnime(mixed $anime): void
{
$this->anime = Anime::from($anime);
}
diff --git a/src/AnimeClient/Types/Character.php b/src/AnimeClient/Types/Character.php
index d9500914..e68c4259 100644
--- a/src/AnimeClient/Types/Character.php
+++ b/src/AnimeClient/Types/Character.php
@@ -27,7 +27,7 @@ final class Character extends AbstractType {
/**
* @var string
*/
- public $id;
+ public string $id;
public array $included = [];
@@ -39,7 +39,7 @@ final class Character extends AbstractType {
public array $otherNames = [];
- public function setMedia ($media): void
+ public function setMedia (mixed $media): void
{
$this->media = Media::from($media);
}
diff --git a/src/AnimeClient/Types/Config.php b/src/AnimeClient/Types/Config.php
index d3f2d7d7..9de10ffd 100644
--- a/src/AnimeClient/Types/Config.php
+++ b/src/AnimeClient/Types/Config.php
@@ -47,8 +47,9 @@ class Config extends AbstractType {
/**
* The list to redirect to from the root url
+ * 'anime' or 'manga'
*
- * @var 'anime' | 'manga'
+ * @var string|null
*/
public ?string $default_list;
@@ -59,7 +60,10 @@ class Config extends AbstractType {
public ?string $default_manga_list_path;
/**
- * @var 'cover_view' | 'list_view'
+ * Default list view type
+ * 'cover_view' or 'list_view'
+ *
+ * @var string
*/
public ?string $default_view_type;
@@ -70,17 +74,18 @@ class Config extends AbstractType {
/**
* @var string|bool
*/
- public $show_anime_collection = FALSE;
+ public string|bool $show_anime_collection = FALSE;
/**
* @var string|bool
*/
- public $show_manga_collection = FALSE;
+ public string|bool $show_manga_collection = FALSE;
/**
* CSS theme: light, dark, or auto-switching
+ * 'auto', 'light', or 'dark'
*
- * @var 'auto' | 'light' | 'dark'
+ * @var string|null
*/
public ?string $theme = 'auto';
@@ -116,17 +121,17 @@ class Config extends AbstractType {
public ?string $view_path;
- public function setAnilist ($data): void
+ public function setAnilist (mixed $data): void
{
$this->anilist = Config\Anilist::from($data);
}
- public function setCache ($data): void
+ public function setCache (mixed $data): void
{
$this->cache = Config\Cache::from($data);
}
- public function setDatabase ($data): void
+ public function setDatabase (mixed $data): void
{
$this->database = Config\Database::from($data);
}
diff --git a/src/AnimeClient/Types/FormItem.php b/src/AnimeClient/Types/FormItem.php
index b8d1130a..47a0eb5a 100644
--- a/src/AnimeClient/Types/FormItem.php
+++ b/src/AnimeClient/Types/FormItem.php
@@ -23,18 +23,16 @@ class FormItem extends AbstractType {
/**
* @var string|int
*/
- public $id;
-
- public ?string $anilist_item_id;
+ public string|int $id;
/**
- * @var string|int
+ * @var string|int|null
*/
- public $mal_id;
+ public string|int|null $mal_id;
public ?FormItemData $data;
- public function setData($value): void
+ public function setData(mixed $value): void
{
$this->data = FormItemData::from($value);
}
diff --git a/src/AnimeClient/Types/MangaPage.php b/src/AnimeClient/Types/MangaPage.php
index a889e120..08972090 100644
--- a/src/AnimeClient/Types/MangaPage.php
+++ b/src/AnimeClient/Types/MangaPage.php
@@ -23,12 +23,12 @@ use Aviat\AnimeClient\API\Kitsu\Enum\MangaPublishingStatus;
*/
final class MangaPage extends AbstractType {
/**
- * @var string
+ * @var string|null
*/
public ?string $age_rating;
/**
- * @var string
+ * @var string|null
*/
public ?string $age_rating_guide;
@@ -38,14 +38,14 @@ final class MangaPage extends AbstractType {
public array $characters;
/**
- * @var int
+ * @var int|null
*/
- public $chapter_count;
+ public ?int $chapter_count;
/**
- * @var string
+ * @var string|null
*/
- public $cover_image;
+ public ?string $cover_image;
/**
* @var array
@@ -60,15 +60,15 @@ final class MangaPage extends AbstractType {
/**
* @var string
*/
- public $id;
+ public string $id;
/**
* @var string
*/
- public $manga_type;
+ public string $manga_type;
/**
- * @var MangaPublishingStatus
+ * @var string
*/
public string $status = MangaPublishingStatus::FINISHED;
@@ -103,7 +103,7 @@ final class MangaPage extends AbstractType {
public string $url;
/**
- * @var int
+ * @var int|null
*/
public ?int $volume_count;
}
diff --git a/src/AnimeClient/Types/Person.php b/src/AnimeClient/Types/Person.php
index 675f2b56..d9afd8ee 100644
--- a/src/AnimeClient/Types/Person.php
+++ b/src/AnimeClient/Types/Person.php
@@ -21,7 +21,7 @@ namespace Aviat\AnimeClient\Types;
*/
final class Person extends AbstractType {
- public $id;
+ public string $id;
public ?string $name;
diff --git a/src/AnimeClient/UrlGenerator.php b/src/AnimeClient/UrlGenerator.php
index b4c99b56..19cb7262 100644
--- a/src/AnimeClient/UrlGenerator.php
+++ b/src/AnimeClient/UrlGenerator.php
@@ -49,7 +49,7 @@ class UrlGenerator extends RoutingBase {
/**
* Get the base url for css/js/images
*
- * @param array $args
+ * @param string ...$args
* @return string
*/
public function assetUrl(string ...$args): string
@@ -72,7 +72,7 @@ class UrlGenerator extends RoutingBase {
{
$path = trim($path, '/');
- $path = preg_replace('`{/.*?}`i', '', $path);
+ $path = preg_replace('`{/.*?}`i', '', $path) ?? "";
// Remove any optional parameters from the route
// and replace them with existing route parameters, if they exist
@@ -87,7 +87,7 @@ class UrlGenerator extends RoutingBase {
$segments[$i + 1] = '';
}
- $pathSegments[$i] = preg_replace('`{.*?}`', $segments[$i + 1], $pathSegments[$i]);
+ $pathSegments[$i] = preg_replace('`{.*?}`', $segments[$i + 1], $pathSegments[$i] ?? '');
}
$path = implode('/', $pathSegments);
diff --git a/src/AnimeClient/Util.php b/src/AnimeClient/Util.php
index 940b976e..fcb77751 100644
--- a/src/AnimeClient/Util.php
+++ b/src/AnimeClient/Util.php
@@ -57,11 +57,11 @@ class Util {
/**
* Absolutely equal?
*
- * @param $left
- * @param $right
+ * @param mixed $left
+ * @param mixed $right
* @return bool
*/
- public static function eq($left, $right): bool
+ public static function eq(mixed $left, mixed $right): bool
{
return $left === $right;
}
diff --git a/src/Ion/Di/Container.php b/src/Ion/Di/Container.php
index cecafd1f..ac545d21 100644
--- a/src/Ion/Di/Container.php
+++ b/src/Ion/Di/Container.php
@@ -29,21 +29,21 @@ class Container implements ContainerInterface {
*
* @var Callable[]
*/
- protected $container = [];
+ protected array $container = [];
/**
* Array of object instances
*
* @var array
*/
- protected $instances = [];
+ protected array $instances = [];
/**
* Map of logger instances
*
* @var array
*/
- protected $loggers = [];
+ protected array $loggers = [];
/**
* Constructor
@@ -66,7 +66,7 @@ class Container implements ContainerInterface {
*
* @return mixed Entry.
*/
- public function get($id)
+ public function get($id): mixed
{
if ( ! \is_string($id))
{
@@ -99,7 +99,7 @@ class Container implements ContainerInterface {
* @throws ContainerException - Error while retrieving the entry.
* @return mixed
*/
- public function getNew($id, array $args = NULL)
+ public function getNew($id, array $args = NULL): mixed
{
if ( ! \is_string($id))
{
@@ -141,7 +141,7 @@ class Container implements ContainerInterface {
* @throws NotFoundException - No entry was found for this identifier.
* @return ContainerInterface
*/
- public function setInstance(string $id, $value): ContainerInterface
+ public function setInstance(string $id, mixed $value): ContainerInterface
{
if ( ! $this->has($id))
{
@@ -209,15 +209,20 @@ class Container implements ContainerInterface {
* @param mixed $obj
* @return mixed
*/
- private function applyContainer($obj)
+ private function applyContainer(mixed $obj): mixed
{
- $trait_name = ContainerAware::class;
- $interface_name = ContainerAwareInterface::class;
+ $traitName = ContainerAware::class;
+ $interfaceName = ContainerAwareInterface::class;
- $uses_trait = \in_array($trait_name, class_uses($obj), TRUE);
- $implements_interface = \in_array($interface_name, class_implements($obj), TRUE);
+ $traits = class_uses($obj);
+ $traitsUsed = (is_array($traits)) ? $traits : [];
+ $usesTrait = in_array($traitName, $traitsUsed, TRUE);
- if ($uses_trait || $implements_interface)
+ $interfaces = class_implements($obj);
+ $implemented = (is_array($interfaces)) ? $interfaces : [];
+ $implementsInterface = in_array($interfaceName, $implemented, TRUE);
+
+ if ($usesTrait || $implementsInterface)
{
$obj->setContainer($this);
}
diff --git a/src/Ion/HttpViewInterface.php b/src/Ion/HttpViewInterface.php
new file mode 100644
index 00000000..e817b3c7
--- /dev/null
+++ b/src/Ion/HttpViewInterface.php
@@ -0,0 +1,32 @@
+
+ * @copyright 2015 - 2021 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 5.2
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\Ion;
+
+/**
+ * View Interface abstracting an HTTP Response
+ */
+interface HttpViewInterface extends ViewInterface {
+
+ /**
+ * Set the status code of the request
+ *
+ * @param int $code
+ * @throws \InvalidArgumentException
+ * @return self
+ */
+ public function setStatusCode(int $code): self;
+}
\ No newline at end of file
diff --git a/src/Ion/Json.php b/src/Ion/Json.php
index 3711c2bb..fbfc5f3f 100644
--- a/src/Ion/Json.php
+++ b/src/Ion/Json.php
@@ -32,11 +32,12 @@ class Json {
* @throws JsonException
* @return string
*/
- public static function encode($data, $options = 0, $depth = 512): string
+ public static function encode(mixed $data, int $options = 0, int $depth = 512): string
{
$json = json_encode($data, $options, $depth);
self::check_json_error();
- return $json;
+
+ return ($json !== FALSE) ? $json : '';
}
/**
@@ -47,12 +48,14 @@ class Json {
* @param int $jsonOptions - Options to pass to json_encode
* @param int $fileOptions - Options to pass to file_get_contents
* @throws JsonException
- * @return int
+ * @return bool
*/
- public static function encodeFile(string $filename, $data, int $jsonOptions = 0, int $fileOptions = 0): int
+ public static function encodeFile(string $filename, mixed $data, int $jsonOptions = 0, int $fileOptions = 0): bool
{
$json = self::encode($data, $jsonOptions);
- return file_put_contents($filename, $json, $fileOptions);
+
+ $res = file_put_contents($filename, $json, $fileOptions);
+ return $res !== FALSE;
}
/**
@@ -65,7 +68,7 @@ class Json {
* @throws JsonException
* @return mixed
*/
- public static function decode($json, bool $assoc = TRUE, int $depth = 512, int $options = 0)
+ public static function decode(?string $json, bool $assoc = TRUE, int $depth = 512, int $options = 0): mixed
{
// Don't try to decode null
if ($json === NULL)
@@ -89,9 +92,11 @@ class Json {
* @throws JsonException
* @return mixed
*/
- public static function decodeFile(string $filename, bool $assoc = TRUE, int $depth = 512, int $options = 0)
+ public static function decodeFile(string $filename, bool $assoc = TRUE, int $depth = 512, int $options = 0): mixed
{
- $json = file_get_contents($filename);
+ $rawJson = file_get_contents($filename);
+ $json = ($rawJson !== FALSE) ? $rawJson : '';
+
return self::decode($json, $assoc, $depth, $options);
}
diff --git a/src/Ion/Transformer/AbstractTransformer.php b/src/Ion/Transformer/AbstractTransformer.php
index 2beeee19..c65a2ab9 100644
--- a/src/Ion/Transformer/AbstractTransformer.php
+++ b/src/Ion/Transformer/AbstractTransformer.php
@@ -28,7 +28,7 @@ abstract class AbstractTransformer implements TransformerInterface {
* @param array|object $item
* @return mixed
*/
- abstract public function transform($item);
+ abstract public function transform(array|object $item): mixed;
/**
* Transform a set of structures
diff --git a/src/Ion/Transformer/TransformerInterface.php b/src/Ion/Transformer/TransformerInterface.php
index 1c7d0160..72e94c17 100644
--- a/src/Ion/Transformer/TransformerInterface.php
+++ b/src/Ion/Transformer/TransformerInterface.php
@@ -27,5 +27,5 @@ interface TransformerInterface {
* @param array|object $item
* @return mixed
*/
- public function transform($item);
+ public function transform(array|object $item): mixed;
}
\ No newline at end of file
diff --git a/src/Ion/Type/ArrayType.php b/src/Ion/Type/ArrayType.php
index cb3a9353..03050dbe 100644
--- a/src/Ion/Type/ArrayType.php
+++ b/src/Ion/Type/ArrayType.php
@@ -101,7 +101,7 @@ class ArrayType {
* @return mixed
* @throws InvalidArgumentException
*/
- public function __call(string $method, array $args)
+ public function __call(string $method, array $args): mixed
{
// Simple mapping for the majority of methods
if (array_key_exists($method, $this->nativeMethods))
@@ -128,7 +128,7 @@ class ArrayType {
* @param int|string|array $key
* @return bool
*/
- public function hasKey($key): bool
+ public function hasKey(int|string|array $key): bool
{
if (\is_array($key))
{
@@ -158,7 +158,7 @@ class ArrayType {
* @param mixed $value
* @return array
*/
- public function fill(int $start_index, int $num, $value): array
+ public function fill(int $start_index, int $num, mixed $value): array
{
return array_fill($start_index, $num, $value);
}
@@ -179,9 +179,9 @@ class ArrayType {
*
* @param mixed $value
* @param bool $strict
- * @return false|integer|string
+ * @return false|integer|string|null
*/
- public function search($value, bool $strict = TRUE)
+ public function search(mixed $value, bool $strict = TRUE): int|string|false|null
{
return array_search($value, $this->arr, $strict);
}
@@ -193,7 +193,7 @@ class ArrayType {
* @param bool $strict
* @return bool
*/
- public function has($value, bool $strict = TRUE): bool
+ public function has(mixed $value, bool $strict = TRUE): bool
{
return \in_array($value, $this->arr, $strict);
}
@@ -204,7 +204,7 @@ class ArrayType {
* @param string|integer|null $key
* @return mixed
*/
- public function &get($key = NULL)
+ public function &get(string|int|null $key = NULL): mixed
{
$value = NULL;
if ($key === NULL)
@@ -229,7 +229,7 @@ class ArrayType {
* @param mixed $value
* @return ArrayType
*/
- public function set($key, $value): ArrayType
+ public function set(mixed $key, mixed $value): ArrayType
{
$this->arr[$key] = $value;
return $this;
@@ -244,7 +244,7 @@ class ArrayType {
* @param array $key An array of keys of the array
* @return mixed
*/
- public function &getDeepKey(array $key)
+ public function &getDeepKey(array $key): mixed
{
$pos =& $this->arr;
@@ -273,7 +273,7 @@ class ArrayType {
* @param mixed $value
* @return array
*/
- public function setDeepKey(array $key, $value): array
+ public function setDeepKey(array $key, mixed $value): array
{
$pos =& $this->arr;
diff --git a/src/Ion/Type/StringType.php b/src/Ion/Type/StringType.php
index a90da7d6..4a61c380 100644
--- a/src/Ion/Type/StringType.php
+++ b/src/Ion/Type/StringType.php
@@ -27,7 +27,7 @@ class StringType extends Stringy {
* Alias for `create` static constructor
*
* @param string $str
- * @return $this
+ * @return self
*/
public static function from(string $str): self
{
diff --git a/src/Ion/View/HtmlView.php b/src/Ion/View/HtmlView.php
index bcc813d0..ad24c6e5 100644
--- a/src/Ion/View/HtmlView.php
+++ b/src/Ion/View/HtmlView.php
@@ -18,8 +18,6 @@ namespace Aviat\Ion\View;
use Aviat\Ion\Di\ContainerAware;
use Aviat\Ion\Di\ContainerInterface;
-use Aviat\Ion\Di\Exception\ContainerException;
-use Aviat\Ion\Di\Exception\NotFoundException;
use Laminas\Diactoros\Response\HtmlResponse;
use const EXTR_OVERWRITE;
@@ -40,8 +38,6 @@ class HtmlView extends HttpView {
* Create the Html View
*
* @param ContainerInterface $container
- * @throws ContainerException
- * @throws NotFoundException
*/
public function __construct(ContainerInterface $container)
{
@@ -57,6 +53,7 @@ class HtmlView extends HttpView {
* @param string $path
* @param array $data
* @return string
+ * @throws \Throwable
*/
public function renderTemplate(string $path, array $data): string
{
@@ -69,13 +66,12 @@ class HtmlView extends HttpView {
ob_start();
extract($data, EXTR_OVERWRITE);
include_once $path;
- $buffer = ob_get_clean();
+ $rawBuffer = ob_get_clean();
+ $buffer = ($rawBuffer === FALSE) ? '' : $rawBuffer;
// Very basic html minify, that won't affect content between html tags
- $buffer = preg_replace('/>\s+', '> <', $buffer);
-
- return $buffer;
+ return preg_replace('/>\s+', '> <', $buffer) ?? $buffer;
}
}
// End of HtmlView.php
\ No newline at end of file
diff --git a/src/Ion/View/HttpView.php b/src/Ion/View/HttpView.php
index 21a4b041..c0b65913 100644
--- a/src/Ion/View/HttpView.php
+++ b/src/Ion/View/HttpView.php
@@ -16,7 +16,7 @@
namespace Aviat\Ion\View;
-use Aviat\Ion\ViewInterface;
+use Aviat\Ion\HttpViewInterface;
use Laminas\Diactoros\Response;
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
@@ -26,7 +26,7 @@ use Psr\Http\Message\ResponseInterface;
/**
* Base view class for Http output
*/
-class HttpView implements ViewInterface{
+class HttpView implements HttpViewInterface{
/**
* HTTP response Object
@@ -103,9 +103,9 @@ class HttpView implements ViewInterface{
* Set the output string
*
* @param mixed $string
- * @return HttpView
+ * @return HttpViewInterface
*/
- public function setOutput($string): self
+ public function setOutput($string): HttpViewInterface
{
$this->response->getBody()->write($string);
@@ -117,9 +117,9 @@ class HttpView implements ViewInterface{
* Append additional output.
*
* @param string $string
- * @return HttpView
+ * @return HttpViewInterface
*/
- public function appendOutput(string $string): self
+ public function appendOutput(string $string): HttpViewInterface
{
return $this->setOutput($string);
}
diff --git a/src/Ion/View/JsonView.php b/src/Ion/View/JsonView.php
index 8f27801d..470076d4 100644
--- a/src/Ion/View/JsonView.php
+++ b/src/Ion/View/JsonView.php
@@ -17,6 +17,7 @@
namespace Aviat\Ion\View;
use Aviat\Ion\Json;
+use Aviat\Ion\HttpViewInterface;
/**
* View class to serialize Json
@@ -34,9 +35,9 @@ class JsonView extends HttpView {
* Set the output string
*
* @param mixed $string
- * @return JsonView
+ * @return HttpViewInterface
*/
- public function setOutput($string): self
+ public function setOutput(mixed $string): HttpViewInterface
{
if ( ! is_string($string))
{
diff --git a/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 0__1.yml b/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 0__1.yml
index 22fb6164..814b33e9 100644
--- a/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 0__1.yml
+++ b/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 0__1.yml
@@ -1,6 +1,5 @@
empty: false
id: 14047981
-anilist_item_id: null
mal_id: null
data:
empty: false
diff --git a/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 1__1.yml b/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 1__1.yml
index 6769276d..6f631375 100644
--- a/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 1__1.yml
+++ b/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 1__1.yml
@@ -1,6 +1,5 @@
empty: false
id: 14047981
-anilist_item_id: null
mal_id: '12345'
data:
empty: false
diff --git a/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 2__1.yml b/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 2__1.yml
index adc5fcbe..98e0c061 100644
--- a/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 2__1.yml
+++ b/tests/AnimeClient/API/Kitsu/Transformer/__snapshots__/AnimeListTransformerTest__testUntransform with data set 2__1.yml
@@ -1,6 +1,5 @@
empty: false
id: 14047983
-anilist_item_id: null
mal_id: '12347'
data:
empty: false
diff --git a/tests/AnimeClient/KitsuTest.php b/tests/AnimeClient/KitsuTest.php
index 143defa6..7a099a6f 100644
--- a/tests/AnimeClient/KitsuTest.php
+++ b/tests/AnimeClient/KitsuTest.php
@@ -122,4 +122,36 @@ class KitsuTest extends TestCase {
$this->assertEquals($expected, $actual);
}
+
+ public function testFilterLocalizedTitles()
+ {
+ $input = [
+ 'canonical' => 'foo',
+ 'localized' => [
+ 'en' => 'Foo the Movie',
+ 'fr' => '',
+ 'jp' => NULL,
+ ],
+ 'alternatives' => [],
+ ];
+
+ $actual = Kitsu::filterLocalizedTitles($input);
+
+ $this->assertEquals(['Foo the Movie'], $actual);
+ }
+
+ public function testGetFilteredTitles()
+ {
+ $input = [
+ 'canonical' => 'foo',
+ 'localized' => [
+ 'en' => 'Foo the Movie'
+ ],
+ 'alternatives' => [],
+ ];
+
+ $actual = Kitsu::getFilteredTitles($input);
+
+ $this->assertEquals(['Foo the Movie'], $actual);
+ }
}
\ No newline at end of file
diff --git a/tests/Ion/mocks.php b/tests/Ion/mocks.php
index 0a28b385..c0a2f755 100644
--- a/tests/Ion/mocks.php
+++ b/tests/Ion/mocks.php
@@ -66,7 +66,7 @@ class FriendTestClass extends FriendParentTestClass {
class TestTransformer extends AbstractTransformer {
- public function transform($item)
+ public function transform(array|object $item): array
{
$out = [];
$genre_list = (array) $item;