Version 5.1 - All the GraphQL #32

Closed
timw4mail wants to merge 1160 commits from develop into master
19 changed files with 128 additions and 297 deletions
Showing only changes of commit 951f4362db - Show all commits

View File

@ -50,7 +50,8 @@
"spatie/phpunit-snapshot-assertions": "^2.2.1", "spatie/phpunit-snapshot-assertions": "^2.2.1",
"squizlabs/php_codesniffer": "^3.2.2", "squizlabs/php_codesniffer": "^3.2.2",
"symfony/var-dumper": "^4.4.1", "symfony/var-dumper": "^4.4.1",
"theseer/phpdox": "*" "theseer/phpdox": "*",
"vimeo/psalm": "^3.7"
}, },
"scripts": { "scripts": {
"build": "vendor/bin/robo build", "build": "vendor/bin/robo build",
@ -58,10 +59,11 @@
"build:js": "cd public && npm run build:js && cd ..", "build:js": "cd public && npm run build:js && cd ..",
"clean": "vendor/bin/robo clean", "clean": "vendor/bin/robo clean",
"coverage": "phpdbg -qrr -- vendor/bin/phpunit -c build", "coverage": "phpdbg -qrr -- vendor/bin/phpunit -c build",
"phpstan": "phpstan analyse -l 4 -c phpstan.neon src tests ./console index.php", "phpstan": "phpstan analyse -c phpstan.neon",
"watch:css": "cd public && npm run watch:css", "watch:css": "cd public && npm run watch:css",
"watch:js": "cd public && npm run watch:js", "watch:js": "cd public && npm run watch:js",
"test": "vendor/bin/phpunit" "test": "vendor/bin/phpunit -c build --no-coverage",
"test-update": "vendor/bin/phpunit -c build --no-coverage -d --update-snapshots"
}, },
"scripts-descriptions": { "scripts-descriptions": {
"build": "Generate the api docs", "build": "Generate the api docs",

View File

@ -1,9 +1,18 @@
parameters: parameters:
checkGenericClassInNonGenericObjectType: false
inferPrivatePropertyTypeFromConstructor: true
level: 7
autoload_files: autoload_files:
- %rootDir%/../../../tests/mocks.php - %rootDir%/../../../tests/mocks.php
paths:
- src
- tests
- ./console
- index.php
ignoreErrors: ignoreErrors:
- '#Access to an undefined property Aviat\\\Ion\\\Friend::\$[a-zA-Z0-9_]+#' - '#Access to an undefined property Aviat\\\Ion\\\Friend::\$[a-zA-Z0-9_]+#'
- '#Call to an undefined method Aviat\\\Ion\\\Friend::[a-zA-Z0-9_]+\(\)#' - '#Call to an undefined method Aviat\\\Ion\\\Friend::[a-zA-Z0-9_]+\(\)#'
- '#Call to an undefined method Aura\\\Html\\\HelperLocator::[a-zA-Z0-9_]+\(\)#' - '#Call to an undefined method Aura\\\Html\\\HelperLocator::[a-zA-Z0-9_]+\(\)#'
- '#Undefined variable: \$var#'
- '#Property Amp\\Artax\\Internal\\RequestCycle::\$[a-zA-Z0-9_]+#' - '#Property Amp\\Artax\\Internal\\RequestCycle::\$[a-zA-Z0-9_]+#'
excludes_analyse:
- tests/mocks.php

55
psalm.xml Normal file
View File

@ -0,0 +1,55 @@
<?xml version="1.0"?>
<psalm
totallyTyped="false"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
<issueHandlers>
<LessSpecificReturnType errorLevel="info" />
<!-- level 3 issues - slightly lazy code writing, but provably low false-negatives -->
<DeprecatedMethod errorLevel="info" />
<DeprecatedProperty errorLevel="info" />
<DeprecatedClass errorLevel="info" />
<DeprecatedConstant errorLevel="info" />
<DeprecatedFunction errorLevel="info" />
<DeprecatedInterface errorLevel="info" />
<DeprecatedTrait errorLevel="info" />
<InternalMethod errorLevel="info" />
<InternalProperty errorLevel="info" />
<InternalClass errorLevel="info" />
<MissingClosureReturnType errorLevel="info" />
<MissingReturnType errorLevel="info" />
<MissingPropertyType errorLevel="info" />
<InvalidDocblock errorLevel="info" />
<MisplacedRequiredParam errorLevel="info" />
<PropertyNotSetInConstructor errorLevel="info" />
<MissingConstructor errorLevel="info" />
<MissingClosureParamType errorLevel="info" />
<MissingParamType errorLevel="info" />
<RedundantCondition errorLevel="info" />
<DocblockTypeContradiction errorLevel="info" />
<RedundantConditionGivenDocblockType errorLevel="info" />
<UnresolvableInclude errorLevel="info" />
<RawObjectIteration errorLevel="info" />
<InvalidStringClass errorLevel="info" />
</issueHandlers>
</psalm>

View File

@ -65,7 +65,7 @@ class APIRequestBuilder {
/** /**
* The current request * The current request
* @var \Amp\Artax\Request * @var Request
*/ */
protected $request; protected $request;
@ -219,14 +219,14 @@ class APIRequestBuilder {
/** /**
* Return the promise for the current request * Return the promise for the current request
* *
* @return Request
* @throws \Throwable * @throws \Throwable
* @return \Amp\Artax\Request
*/ */
public function getFullRequest(): Request public function getFullRequest(): Request
{ {
$this->buildUri(); $this->buildUri();
if ($this->logger) if ($this->logger !== NULL)
{ {
$this->logger->debug('API Request', [ $this->logger->debug('API Request', [
'request_url' => $this->request->getUri(), 'request_url' => $this->request->getUri(),

View File

@ -25,6 +25,8 @@ use Aviat\AnimeClient\API\Anilist;
use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus}; use Aviat\AnimeClient\API\Mapping\{AnimeWatchingStatus, MangaReadingStatus};
use Aviat\AnimeClient\Types\FormItem; use Aviat\AnimeClient\Types\FormItem;
use Aviat\Ion\Json; use Aviat\Ion\Json;
use Aviat\Ion\Di\Exception\ContainerException;
use Aviat\Ion\Di\Exception\NotFoundException;
/** /**
* Anilist API Model * Anilist API Model
@ -92,8 +94,8 @@ final class Model
* *
* @param string $type * @param string $type
* @return array * @return array
* @throws \Aviat\Ion\Di\Exception\ContainerException * @throws ContainerException
* @throws \Aviat\Ion\Di\Exception\NotFoundException * @throws NotFoundException
*/ */
public function getSyncList(string $type = 'anime'): array public function getSyncList(string $type = 'anime'): array
{ {
@ -144,7 +146,7 @@ final class Model
]; ];
} }
return $this->listItem->create($createData, $type); return $this->listItem->create($createData);
} }
/** /**

View File

@ -16,6 +16,8 @@
namespace Aviat\AnimeClient\API\Kitsu; namespace Aviat\AnimeClient\API\Kitsu;
use Aura\Session\Segment;
use const Aviat\AnimeClient\SESSION_SEGMENT; use const Aviat\AnimeClient\SESSION_SEGMENT;
use Aviat\AnimeClient\API\{ use Aviat\AnimeClient\API\{
@ -23,7 +25,6 @@ use Aviat\AnimeClient\API\{
Kitsu as K Kitsu as K
}; };
use Aviat\Ion\Di\{ContainerAware, ContainerInterface}; use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
use Exception;
/** /**
* Kitsu API Authentication * Kitsu API Authentication
@ -42,7 +43,7 @@ final class Auth {
/** /**
* Session object * Session object
* *
* @var \Aura\Session\Segment * @var Segment
*/ */
private $segment; private $segment;

View File

@ -137,6 +137,9 @@ final class ListItem implements ListItemInterface {
return $request->getFullRequest(); return $request->getFullRequest();
} }
/**
* @return false|string
*/
private function getAuthHeader() private function getAuthHeader()
{ {
$cache = $this->getContainer()->get('cache'); $cache = $this->getContainer()->get('cache');

View File

@ -142,23 +142,24 @@ final class CharacterTransformer extends AbstractTransformer {
foreach ($role['relationships']['person']['people'] as $pid => $peoples) foreach ($role['relationships']['person']['people'] as $pid => $peoples)
{ {
$p = $peoples; $p = $peoples;
$person = $p['attributes'];
$person['id'] = $pid;
$person['image'] = $person['image']['original'];
uasort($role['relationships']['media']['anime'], static function ($a, $b) {
return $a['attributes']['canonicalTitle'] <=> $b['attributes']['canonicalTitle'];
});
$item = [
'person' => $person,
'series' => $role['relationships']['media']['anime']
];
$output[$roleName][$language][] = $item;
} }
}
$person = $p['attributes']; else
$person['id'] = $pid;
$person['image'] = $person['image']['original'];
uasort($role['relationships']['media']['anime'], function ($a, $b) {
return $a['attributes']['canonicalTitle'] <=> $b['attributes']['canonicalTitle'];
});
$item = [
'person' => $person,
'series' => $role['relationships']['media']['anime']
];
$output[$roleName][$language][] = $item;
} else
{ {
foreach ($role['relationships']['person']['people'] as $pid => $person) foreach ($role['relationships']['person']['people'] as $pid => $person)
{ {

View File

@ -130,6 +130,9 @@ final class MangaTransformer extends AbstractTransformer {
]); ]);
} }
/**
* @return int|null|string
*/
private function count(int $value = NULL) private function count(int $value = NULL)
{ {
return ((int)$value === 0) return ((int)$value === 0)

View File

@ -62,7 +62,12 @@ final class UpdateThumbnails extends ClearThumbnails {
$this->echoBox('Finished regenerating all thumbnails'); $this->echoBox('Finished regenerating all thumbnails');
} }
public function getImageList() /**
* @return array-key[][]
*
* @psalm-return array{anime: list<array-key>, manga: list<array-key>}
*/
public function getImageList(): array
{ {
$mangaList = $this->kitsuModel->getFullRawMangaList(); $mangaList = $this->kitsuModel->getFullRawMangaList();
$includes = JsonAPI::organizeIncludes($mangaList['included']); $includes = JsonAPI::organizeIncludes($mangaList['included']);

View File

@ -16,6 +16,8 @@
namespace Aviat\AnimeClient\Controller; namespace Aviat\AnimeClient\Controller;
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
use function Amp\Promise\wait; use function Amp\Promise\wait;
use function Aviat\AnimeClient\getResponse; use function Aviat\AnimeClient\getResponse;
use function Aviat\AnimeClient\createPlaceholderImage; use function Aviat\AnimeClient\createPlaceholderImage;
@ -32,17 +34,14 @@ final class Images extends BaseController {
* @param string $type The category of image * @param string $type The category of image
* @param string $file The filename to look for * @param string $file The filename to look for
* @param bool $display Whether to output the image to the server * @param bool $display Whether to output the image to the server
* @throws \Aviat\Ion\Di\ContainerException
* @throws \Aviat\Ion\Di\NotFoundException
* @throws \InvalidArgumentException
* @throws \TypeError
* @throws \Error
* @throws \Throwable
* @return void * @return void
* @throws NotFoundException
* @throws \Throwable
* @throws ContainerException
*/ */
public function cache(string $type, string $file, $display = TRUE): void public function cache(string $type, string $file, $display = TRUE): void
{ {
$currentUrl = $this->request->getUri()->__toString(); $currentUrl = (string)$this->request->getUri();
$kitsuUrl = 'https://media.kitsu.io/'; $kitsuUrl = 'https://media.kitsu.io/';
$fileName = str_replace('-original', '', $file); $fileName = str_replace('-original', '', $file);

View File

@ -37,7 +37,7 @@ abstract class AbstractType implements ArrayAccess, Countable {
* *
* @param mixed $data * @param mixed $data
*/ */
public function __construct($data = []) final public function __construct($data = [])
{ {
$typeKeys = array_keys((array)$this); $typeKeys = array_keys((array)$this);
$dataKeys = array_keys((array)$data); $dataKeys = array_keys((array)$data);
@ -187,7 +187,7 @@ abstract class AbstractType implements ArrayAccess, Countable {
{ {
$object = $parent ?? $this; $object = $parent ?? $this;
if (is_scalar($object) || empty($object)) if (is_scalar($object) || $object === NULL)
{ {
return $object; return $object;
} }

View File

@ -16,7 +16,8 @@
namespace Aviat\AnimeClient; namespace Aviat\AnimeClient;
use Aviat\Ion\Di\{ContainerAware, ContainerInterface}; use Aviat\Ion\Di\{ContainerAware, ContainerInterface};
use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException};
/** /**
* Utility method class * Utility method class
@ -45,8 +46,8 @@ class Util {
* Set up the Util class * Set up the Util class
* *
* @param ContainerInterface $container * @param ContainerInterface $container
* @throws \Aviat\Ion\Di\ContainerException * @throws ContainerException
* @throws \Aviat\Ion\Di\NotFoundException * @throws NotFoundException
*/ */
public function __construct(ContainerInterface $container) public function __construct(ContainerInterface $container)
{ {
@ -80,8 +81,8 @@ class Util {
/** /**
* Determine whether to show the sub-menu * Determine whether to show the sub-menu
* *
* @throws \Aviat\Ion\Di\ContainerException * @throws ContainerException
* @throws \Aviat\Ion\Di\NotFoundException * @throws NotFoundException
* @return bool * @return bool
*/ */
public function isViewPage(): bool public function isViewPage(): bool
@ -98,8 +99,8 @@ class Util {
* Determine whether the page is a page with a form, and * Determine whether the page is a page with a form, and
* not suitable for redirection * not suitable for redirection
* *
* @throws \Aviat\Ion\Di\ContainerException * @throws ContainerException
* @throws \Aviat\Ion\Di\NotFoundException * @throws NotFoundException
* @return bool * @return bool
*/ */
public function isFormPage(): bool public function isFormPage(): bool

View File

@ -36,10 +36,10 @@
1 => '小林さんちのメイドラゴン', 1 => '小林さんちのメイドラゴン',
), ),
)), )),
'watching_status' => 'current',
'notes' => NULL, 'notes' => NULL,
'private' => false,
'rewatching' => false, 'rewatching' => false,
'rewatched' => 0, 'rewatched' => 0,
'user_rating' => '-', 'user_rating' => '-',
'private' => false, 'watching_status' => 'current',
)); ));

View File

@ -1,15 +0,0 @@
<?php return Aviat\AnimeClient\Types\FormItem::__set_state(array(
'id' => 14047981,
'anilist_item_id' => NULL,
'mal_id' => NULL,
'data' =>
Aviat\AnimeClient\Types\FormItemData::__set_state(array(
'notes' => 'Very formulaic.',
'private' => false,
'progress' => 38,
'ratingTwenty' => 16,
'reconsumeCount' => 0,
'reconsuming' => false,
'status' => 'current',
)),
));

View File

@ -1,15 +0,0 @@
<?php return Aviat\AnimeClient\Types\FormItem::__set_state(array(
'id' => 14047981,
'anilist_item_id' => NULL,
'mal_id' => '12345',
'data' =>
Aviat\AnimeClient\Types\FormItemData::__set_state(array(
'notes' => 'Very formulaic.',
'private' => true,
'progress' => 38,
'ratingTwenty' => 16,
'reconsumeCount' => 0,
'reconsuming' => true,
'status' => 'current',
)),
));

View File

@ -1,14 +0,0 @@
<?php return Aviat\AnimeClient\Types\FormItem::__set_state(array(
'id' => 14047983,
'anilist_item_id' => NULL,
'mal_id' => '12347',
'data' =>
Aviat\AnimeClient\Types\FormItemData::__set_state(array(
'notes' => '',
'private' => true,
'progress' => 12,
'reconsumeCount' => 0,
'reconsuming' => true,
'status' => 'current',
)),
));

View File

@ -1,201 +0,0 @@
<?php return array (
0 =>
Aviat\AnimeClient\Types\MangaListItem::__set_state(array(
'id' => '15084773',
'mal_id' => '26769',
'chapters' =>
array (
'read' => 67,
'total' => '-',
),
'volumes' =>
array (
'read' => '-',
'total' => '-',
),
'manga' =>
Aviat\AnimeClient\Types\MangaListItemDetail::__set_state(array(
'genres' =>
array (
0 => 'Comedy',
1 => 'Romance',
2 => 'School',
3 => 'Slice of Life',
4 => 'Thriller',
),
'id' => '20286',
'image' => 'https://media.kitsu.io/manga/poster_images/20286/small.jpg?1434293999',
'slug' => 'bokura-wa-minna-kawaisou',
'title' => 'Bokura wa Minna Kawaisou',
'titles' =>
array (
),
'type' => 'Manga',
'url' => 'https://kitsu.io/manga/bokura-wa-minna-kawaisou',
)),
'reading_status' => 'current',
'notes' => '',
'rereading' => false,
'reread' => 0,
'user_rating' => 9,
)),
1 =>
Aviat\AnimeClient\Types\MangaListItem::__set_state(array(
'id' => '15085607',
'mal_id' => '16',
'chapters' =>
array (
'read' => 17,
'total' => 120,
),
'volumes' =>
array (
'read' => '-',
'total' => 14,
),
'manga' =>
Aviat\AnimeClient\Types\MangaListItemDetail::__set_state(array(
'genres' =>
array (
0 => 'Comedy',
1 => 'Ecchi',
2 => 'Harem',
3 => 'Romance',
4 => 'Sports',
),
'id' => '47',
'image' => 'https://media.kitsu.io/manga/poster_images/47/small.jpg?1434249493',
'slug' => 'love-hina',
'title' => 'Love Hina',
'titles' =>
array (
),
'type' => 'Manga',
'url' => 'https://kitsu.io/manga/love-hina',
)),
'reading_status' => 'current',
'notes' => '',
'rereading' => false,
'reread' => 0,
'user_rating' => 7,
)),
2 =>
Aviat\AnimeClient\Types\MangaListItem::__set_state(array(
'id' => '15084529',
'mal_id' => '35003',
'chapters' =>
array (
'read' => 16,
'total' => '-',
),
'volumes' =>
array (
'read' => '-',
'total' => '-',
),
'manga' =>
Aviat\AnimeClient\Types\MangaListItemDetail::__set_state(array(
'genres' =>
array (
0 => 'Comedy',
1 => 'Ecchi',
2 => 'Gender Bender',
3 => 'Romance',
4 => 'School',
5 => 'Sports',
6 => 'Supernatural',
),
'id' => '11777',
'image' => 'https://media.kitsu.io/manga/poster_images/11777/small.jpg?1438784325',
'slug' => 'yamada-kun-to-7-nin-no-majo',
'title' => 'Yamada-kun to 7-nin no Majo',
'titles' =>
array (
0 => 'Yamada-kun and the Seven Witches',
),
'type' => 'Manga',
'url' => 'https://kitsu.io/manga/yamada-kun-to-7-nin-no-majo',
)),
'reading_status' => 'current',
'notes' => '',
'rereading' => false,
'reread' => 0,
'user_rating' => 9,
)),
3 =>
Aviat\AnimeClient\Types\MangaListItem::__set_state(array(
'id' => '15312827',
'mal_id' => '78523',
'chapters' =>
array (
'read' => 68,
'total' => '-',
),
'volumes' =>
array (
'read' => '-',
'total' => '-',
),
'manga' =>
Aviat\AnimeClient\Types\MangaListItemDetail::__set_state(array(
'genres' =>
array (
0 => 'Romance',
1 => 'School',
2 => 'Slice of Life',
),
'id' => '27175',
'image' => 'https://media.kitsu.io/manga/poster_images/27175/small.jpg?1464379411',
'slug' => 'relife',
'title' => 'ReLIFE',
'titles' =>
array (
),
'type' => 'Manga',
'url' => 'https://kitsu.io/manga/relife',
)),
'reading_status' => 'current',
'notes' => '',
'rereading' => false,
'reread' => 0,
'user_rating' => '-',
)),
4 =>
Aviat\AnimeClient\Types\MangaListItem::__set_state(array(
'id' => '15084769',
'mal_id' => '60815',
'chapters' =>
array (
'read' => 43,
'total' => '-',
),
'volumes' =>
array (
'read' => '-',
'total' => '-',
),
'manga' =>
Aviat\AnimeClient\Types\MangaListItemDetail::__set_state(array(
'genres' =>
array (
0 => 'Comedy',
1 => 'School',
2 => 'Slice of Life',
),
'id' => '25491',
'image' => 'https://media.kitsu.io/manga/poster_images/25491/small.jpg?1434305043',
'slug' => 'joshikausei',
'title' => 'Joshikausei',
'titles' =>
array (
),
'type' => 'Manga',
'url' => 'https://kitsu.io/manga/joshikausei',
)),
'reading_status' => 'current',
'notes' => '',
'rereading' => false,
'reread' => 0,
'user_rating' => 8,
)),
);

View File

@ -1,5 +0,0 @@
- null
- null
- null
- null
- null