Add a bumch of soundness checks suggested by PHPStan
All checks were successful
timw4mail/HummingBirdAnimeClient/pipeline/head This commit looks good

This commit is contained in:
Timothy Warren 2021-02-10 17:17:51 -05:00
parent ebd7f811ee
commit 9224751d2d
25 changed files with 190 additions and 126 deletions

View File

@ -122,7 +122,6 @@ final class AnimeListTransformer extends AbstractTransformer {
$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'],

View File

@ -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),

View File

@ -45,7 +45,7 @@ final class MenuGenerator extends UrlGenerator {
/**
* @param ContainerInterface $container
* @return static
* @return self
*/
public static function new(ContainerInterface $container): self
{

View File

@ -92,6 +92,11 @@ final class AnimeCollection extends Collection {
$genres = $this->getGenreList();
$media = $this->getMediaList();
if ($rows === FALSE)
{
return [];
}
foreach($rows as &$row)
{
$id = $row['hummingbird_id'];
@ -128,7 +133,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,10 +169,10 @@ 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)
{
@ -197,10 +208,10 @@ 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)
{
@ -218,7 +229,7 @@ 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)
{
@ -253,11 +264,11 @@ 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)
{
@ -288,7 +299,7 @@ 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)
{
@ -316,10 +327,10 @@ 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)
{
@ -335,7 +346,7 @@ 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)
{
@ -348,6 +359,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 +371,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,7 +387,7 @@ 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)
{
@ -416,7 +437,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 +464,7 @@ final class AnimeCollection extends Collection {
}
}
}
catch (PDOException $e) {}
catch (PDOException) {}
$this->db->resetQuery();
@ -478,7 +505,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'];
@ -609,7 +642,7 @@ final class AnimeCollection extends Collection {
{
$this->db->insertBatch('genres', $insert);
}
catch (PDOException $e)
catch (PDOException)
{
// dump($e);
}
@ -642,7 +675,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'];
}
@ -665,7 +704,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))
{
@ -706,6 +751,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)

View File

@ -67,10 +67,11 @@ 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->validDatabase = str_starts_with($dbFile, 'SQLite format 3');
}
else
{

View File

@ -69,9 +69,7 @@ final class Settings {
{
$output = [];
$settings = $this->getSettings();
foreach($settings as $file => $values)
foreach($this->getSettings() as $file => $values)
{
$values = $values ?? [];

View File

@ -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,8 @@ abstract class AbstractType implements ArrayAccess, Countable {
if (get_parent_class($currentClass) !== FALSE)
{
return (new $currentClass($data))->toArray();
$output = static::class::from($data)->toArray();
return (is_array($output)) ? $output : [];
}
return NULL;
@ -55,7 +56,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 +66,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 +88,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 +103,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 +129,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 +149,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 +200,19 @@ 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 float|bool|null|int|array|string
*/
final public function toArray($parent = null)
final public function toArray(mixed $parent = null): float|null|bool|int|array|string
{
$object = $parent ?? $this;
@ -236,7 +240,8 @@ abstract class AbstractType implements ArrayAccess, Countable {
*/
final public function isEmpty(): bool
{
foreach ($this as $value)
$self = (array)$this->toArray();
foreach ($self as $value)
{
if ( ! empty($value))
{

View File

@ -35,9 +35,9 @@ class Anime extends AbstractType {
public array $genres = [];
/**
* @var string|int
* @var string
*/
public $id = '';
public string $id = '';
public array $included = [];

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -21,7 +21,7 @@ namespace Aviat\AnimeClient\Types;
*/
final class Person extends AbstractType {
public $id;
public string $id;
public ?string $name;

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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
{

View File

@ -69,7 +69,8 @@ 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

View File

@ -103,9 +103,9 @@ class HttpView implements ViewInterface{
* Set the output string
*
* @param mixed $string
* @return HttpView
* @return ViewInterface
*/
public function setOutput($string): self
public function setOutput($string): ViewInterface
{
$this->response->getBody()->write($string);
@ -117,9 +117,9 @@ class HttpView implements ViewInterface{
* Append additional output.
*
* @param string $string
* @return HttpView
* @return ViewInterface
*/
public function appendOutput(string $string): self
public function appendOutput(string $string): ViewInterface
{
return $this->setOutput($string);
}

View File

@ -17,6 +17,7 @@
namespace Aviat\Ion\View;
use Aviat\Ion\Json;
use Aviat\Ion\ViewInterface;
/**
* View class to serialize Json
@ -34,9 +35,9 @@ class JsonView extends HttpView {
* Set the output string
*
* @param mixed $string
* @return JsonView
* @return ViewInterface
*/
public function setOutput($string): self
public function setOutput($string): ViewInterface
{
if ( ! is_string($string))
{

View File

@ -1,6 +1,5 @@
empty: false
id: 14047981
anilist_item_id: null
mal_id: null
data:
empty: false

View File

@ -1,6 +1,5 @@
empty: false
id: 14047981
anilist_item_id: null
mal_id: '12345'
data:
empty: false

View File

@ -1,6 +1,5 @@
empty: false
id: 14047983
anilist_item_id: null
mal_id: '12347'
data:
empty: false