Merge remote-tracking branch 'origin/develop'
This commit is contained in:
commit
db6e089d93
@ -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.
|
||||
|
8
Jenkinsfile
vendored
8
Jenkinsfile
vendored
@ -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'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -17,7 +17,9 @@
|
||||
<directory>../tests/Ion</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<logging/>
|
||||
<logging>
|
||||
<junit outputFile="logs/junit.xml"/>
|
||||
</logging>
|
||||
<php>
|
||||
<server name="HTTP_USER_AGENT" value="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:38.0) Gecko/20100101 Firefox/38.0"/>
|
||||
<server name="HTTP_HOST" value="localhost"/>
|
||||
|
@ -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);
|
||||
}
|
||||
|
14
phpstan.neon
14
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
|
||||
- vendor
|
||||
# These are objects that basically can return anything
|
||||
universalObjectCratesClasses:
|
||||
- Aviat\Ion\Friend
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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.');
|
||||
}
|
||||
|
@ -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([]);
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ use DateTime;
|
||||
|
||||
class MangaListTransformer extends AbstractTransformer {
|
||||
|
||||
public function transform($item)
|
||||
public function transform(array|object $item): MangaListItem
|
||||
{
|
||||
return MangaListItem::from([]);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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'],
|
||||
|
@ -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 = [];
|
||||
|
@ -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' => [],
|
||||
|
@ -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'];
|
||||
}
|
||||
|
@ -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'];
|
||||
|
@ -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'];
|
||||
|
||||
|
@ -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 = [];
|
||||
|
@ -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']);
|
||||
|
||||
|
@ -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 = [];
|
||||
|
@ -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 : '';
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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}";
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 = [];
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -35,9 +35,9 @@ class Anime extends AbstractType {
|
||||
public array $genres = [];
|
||||
|
||||
/**
|
||||
* @var string|int
|
||||
* @var string
|
||||
*/
|
||||
public $id = '';
|
||||
public string $id = '';
|
||||
|
||||
public array $included = [];
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ namespace Aviat\AnimeClient\Types;
|
||||
*/
|
||||
final class Person extends AbstractType {
|
||||
|
||||
public $id;
|
||||
public string $id;
|
||||
|
||||
public ?string $name;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
32
src/Ion/HttpViewInterface.php
Normal file
32
src/Ion/HttpViewInterface.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php declare(strict_types=1);
|
||||
/**
|
||||
* Hummingbird Anime List Client
|
||||
*
|
||||
* An API client for Kitsu to manage anime and manga watch lists
|
||||
*
|
||||
* PHP version 8
|
||||
*
|
||||
* @package HummingbirdAnimeClient
|
||||
* @author Timothy J. Warren <tim@timshomepage.net>
|
||||
* @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;
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -27,5 +27,5 @@ interface TransformerInterface {
|
||||
* @param array|object $item
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform($item);
|
||||
public function transform(array|object $item): mixed;
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
@ -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);
|
||||
}
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -1,6 +1,5 @@
|
||||
empty: false
|
||||
id: 14047981
|
||||
anilist_item_id: null
|
||||
mal_id: null
|
||||
data:
|
||||
empty: false
|
||||
|
@ -1,6 +1,5 @@
|
||||
empty: false
|
||||
id: 14047981
|
||||
anilist_item_id: null
|
||||
mal_id: '12345'
|
||||
data:
|
||||
empty: false
|
||||
|
@ -1,6 +1,5 @@
|
||||
empty: false
|
||||
id: 14047983
|
||||
anilist_item_id: null
|
||||
mal_id: '12347'
|
||||
data:
|
||||
empty: false
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user