diff --git a/composer.json b/composer.json
index 39f80afd..e8037b52 100644
--- a/composer.json
+++ b/composer.json
@@ -60,6 +60,7 @@
"clean": "vendor/bin/robo clean",
"coverage": "phpdbg -qrr -- vendor/bin/phpunit -c build",
"phpstan": "phpstan analyse -c phpstan.neon",
+ "psalm": "vendor/bin/psalm",
"watch:css": "cd public && npm run watch:css",
"watch:js": "cd public && npm run watch:js",
"test": "vendor/bin/phpunit -c build --no-coverage",
diff --git a/phpstan.neon b/phpstan.neon
index 46125efa..7f460fb1 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,12 +1,12 @@
parameters:
checkGenericClassInNonGenericObjectType: false
+ checkMissingIterableValueType: false
inferPrivatePropertyTypeFromConstructor: true
level: 7
autoload_files:
- %rootDir%/../../../tests/mocks.php
paths:
- src
- - tests
- ./console
- index.php
ignoreErrors:
diff --git a/psalm.xml b/psalm.xml
index e2cedae2..42f355b2 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -15,5 +15,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/API/Kitsu/Transformer/CharacterTransformer.php b/src/API/Kitsu/Transformer/CharacterTransformer.php
index 963fcf03..32a90bfa 100644
--- a/src/API/Kitsu/Transformer/CharacterTransformer.php
+++ b/src/API/Kitsu/Transformer/CharacterTransformer.php
@@ -28,8 +28,9 @@ final class CharacterTransformer extends AbstractTransformer {
/**
* @param array $characterData
+ * @return Character
*/
- public function transform(array $characterData): Character
+ public function transform($characterData): Character
{
$data = JsonAPI::organizeData($characterData);
$attributes = $data[0]['attributes'];
diff --git a/src/API/Kitsu/Transformer/PersonTransformer.php b/src/API/Kitsu/Transformer/PersonTransformer.php
index e07876f0..52ee5f60 100644
--- a/src/API/Kitsu/Transformer/PersonTransformer.php
+++ b/src/API/Kitsu/Transformer/PersonTransformer.php
@@ -25,7 +25,11 @@ use Aviat\Ion\Transformer\AbstractTransformer;
*/
final class PersonTransformer extends AbstractTransformer {
- public function transform(array $personData): Person
+ /**
+ * @param array|object $personData
+ * @return Person
+ */
+ public function transform($personData): Person
{
$data = JsonAPI::organizeData($personData);
$included = JsonAPI::organizeIncludes($personData['included']);
diff --git a/src/API/Kitsu/Transformer/UserTransformer.php b/src/API/Kitsu/Transformer/UserTransformer.php
index 96e58578..3ad8f242 100644
--- a/src/API/Kitsu/Transformer/UserTransformer.php
+++ b/src/API/Kitsu/Transformer/UserTransformer.php
@@ -24,9 +24,12 @@ use Aviat\Ion\Transformer\AbstractTransformer;
/**
* Transform user profile data for display
+ *
+ * @param array|object $profileData
+ * @return User
*/
final class UserTransformer extends AbstractTransformer {
- public function transform(array $profileData): User
+ public function transform($profileData): User
{
$orgData = JsonAPI::organizeData($profileData)[0];
$attributes = $orgData['attributes'];
diff --git a/src/Model/AnimeCollection.php b/src/Model/AnimeCollection.php
index 3fa620b8..3cb63220 100644
--- a/src/Model/AnimeCollection.php
+++ b/src/Model/AnimeCollection.php
@@ -75,6 +75,11 @@ final class AnimeCollection extends Collection {
*/
public function getMediaTypeList(): array
{
+ if ($this->validDatabase === FALSE)
+ {
+ return [];
+ }
+
$output = [];
$query = $this->db->select('id, type')
@@ -136,6 +141,11 @@ final class AnimeCollection extends Collection {
*/
public function add($data): void
{
+ if ($this->validDatabase === FALSE)
+ {
+ return;
+ }
+
$id = $data['id'];
// Check that the anime doesn't already exist
@@ -166,13 +176,16 @@ final class AnimeCollection extends Collection {
/**
* Verify that an item was added
*
- * @param $data
* @param array|null|object $data
- *
* @return bool
*/
public function wasAdded($data): bool
{
+ if ($this->validDatabase === FALSE)
+ {
+ return FALSE;
+ }
+
$row = $this->get($data['id']);
return ! empty($row);
@@ -186,6 +199,11 @@ final class AnimeCollection extends Collection {
*/
public function update($data): void
{
+ if ($this->validDatabase === FALSE)
+ {
+ return;
+ }
+
// If there's no id to update, don't update
if ( ! array_key_exists('hummingbird_id', $data))
{
@@ -206,13 +224,17 @@ final class AnimeCollection extends Collection {
/**
* Verify that the collection item was updated
*
- * @param $data
* @param array|null|object $data
*
* @return bool
*/
public function wasUpdated($data): bool
{
+ if ($this->validDatabase === FALSE)
+ {
+ return FALSE;
+ }
+
$row = $this->get($data['hummingbird_id']);
foreach ($data as $key => $value)
@@ -234,6 +256,11 @@ final class AnimeCollection extends Collection {
*/
public function delete($data): void
{
+ if ($this->validDatabase === FALSE)
+ {
+ return;
+ }
+
// If there's no id to update, don't delete
if ( ! array_key_exists('hummingbird_id', $data))
{
@@ -249,9 +276,15 @@ final class AnimeCollection extends Collection {
/**
* @param array|null|object $data
+ * @return bool
*/
public function wasDeleted($data): bool
{
+ if ($this->validDatabase === FALSE)
+ {
+ return FALSE;
+ }
+
$animeRow = $this->get($data['hummingbird_id']);
return empty($animeRow);
@@ -265,6 +298,11 @@ final class AnimeCollection extends Collection {
*/
public function get($kitsuId)
{
+ if ($this->validDatabase === FALSE)
+ {
+ return FALSE;
+ }
+
$query = $this->db->from('anime_set')
->where('hummingbird_id', $kitsuId)
->get();
@@ -280,6 +318,11 @@ final class AnimeCollection extends Collection {
*/
public function getGenreList(array $filter = []): array
{
+ if ($this->validDatabase === FALSE)
+ {
+ return [];
+ }
+
$output = [];
// Catch the missing table PDOException
@@ -337,6 +380,11 @@ final class AnimeCollection extends Collection {
*/
private function updateGenre($animeId): void
{
+ if ($this->validDatabase === FALSE)
+ {
+ return;
+ }
+
// Get api information
$anime = $this->animeModel->getAnimeById($animeId);
@@ -379,6 +427,11 @@ final class AnimeCollection extends Collection {
*/
private function addNewGenres(array $genres): void
{
+ if ($this->validDatabase === FALSE)
+ {
+ return;
+ }
+
$existingGenres = $this->getExistingGenres();
$newGenres = array_diff($genres, $existingGenres);
@@ -416,6 +469,11 @@ final class AnimeCollection extends Collection {
private function getExistingGenres(): array
{
+ if ($this->validDatabase === FALSE)
+ {
+ return [];
+ }
+
$genres = [];
// Get existing genres
@@ -435,6 +493,11 @@ final class AnimeCollection extends Collection {
private function getExistingGenreLinkEntries(): array
{
+ if ($this->validDatabase === FALSE)
+ {
+ return [];
+ }
+
$links = [];
$query = $this->db->select('hummingbird_id, genre_id')
diff --git a/src/Model/Collection.php b/src/Model/Collection.php
index 79cae2cf..27641518 100644
--- a/src/Model/Collection.php
+++ b/src/Model/Collection.php
@@ -19,6 +19,7 @@ namespace Aviat\AnimeClient\Model;
use Aviat\Ion\Di\ContainerInterface;
use PDOException;
+use Query\Query_Builder_Interface;
use function Query;
/**
@@ -28,7 +29,7 @@ class Collection extends DB {
/**
* The query builder object
- * @var \Query\Query_Builder_Interface
+ * @var Query_Builder_Interface
*/
protected $db;
@@ -52,7 +53,13 @@ class Collection extends DB {
$this->db = Query($this->dbConfig);
$this->validDatabase = TRUE;
}
- catch (PDOException $e) {}
+ catch (PDOException $e)
+ {
+ $this->db = Query([
+ 'type' => 'sqlite',
+ 'file' => ':memory:',
+ ]);
+ }
// Is database valid? If not, set a flag so the
// app can be run without a valid database
diff --git a/src/Model/MangaCollection.php b/src/Model/MangaCollection.php
index d652ee0b..1f5a4c65 100644
--- a/src/Model/MangaCollection.php
+++ b/src/Model/MangaCollection.php
@@ -17,7 +17,6 @@
namespace Aviat\AnimeClient\Model;
use Aviat\Ion\Di\ContainerInterface;
-use PDO;
/**
* Model for getting anime collection data
@@ -40,249 +39,5 @@ final class MangaCollection extends Collection {
parent::__construct($container);
$this->mangaModel = $container->get('manga-model');
}
-
- /**
- * Get collection from the database, and organize by media type
- *
- * @return array
- */
- public function getCollection(): array
- {
- $rawCollection = $this->getCollectionFromDatabase();
-
- $collection = [];
-
- foreach ($rawCollection as $row)
- {
- if (array_key_exists($row['media'], $collection))
- {
- $collection[$row['media']][] = $row;
- }
- else
- {
- $collection[$row['media']] = [$row];
- }
- }
-
- return $collection;
- }
-
- /**
- * Get list of media types
- *
- * @return array
- */
- public function getMediaTypeList(): array
- {
- $output = [];
-
- $query = $this->db->select('id, type')
- ->from('media')
- ->get();
-
- foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row)
- {
- $output[$row['id']] = $row['type'];
- }
-
- return $output;
- }
-
- /**
- * Get full collection from the database
- *
- * @return array
- */
- private function getCollectionFromDatabase(): array
- {
- if ( ! $this->validDatabase)
- {
- return [];
- }
-
- $query = $this->db->select('hummingbird_id, slug, title, alternate_title, show_type,
- age_rating, episode_count, episode_length, cover_image, notes, media.type as media')
- ->from('manga_set a')
- ->join('media', 'media.id=a.media_id', 'inner')
- ->order_by('media')
- ->order_by('title')
- ->get();
-
- return $query->fetchAll(PDO::FETCH_ASSOC);
- }
-
- /**
- * Add an item to the anime collection
- *
- * @param array $data
- * @return void
- */
- public function add($data): void
- {
- $anime = (object)$this->mangaModel->getMangaById($data['id']);
- $this->db->set([
- 'hummingbird_id' => $data['id'],
- 'slug' => $anime->slug,
- 'title' => array_shift($anime->titles),
- 'alternate_title' => implode('
', $anime->titles),
- 'show_type' => $anime->show_type,
- 'age_rating' => $anime->age_rating,
- 'cover_image' => $anime->cover_image,
- 'episode_count' => $anime->episode_count,
- 'episode_length' => $anime->episode_length,
- 'media_id' => $data['media_id'],
- 'notes' => $data['notes']
- ])->insert('manga_set');
-
- $this->updateGenre($data['id']);
- }
-
- /**
- * Update a collection item
- *
- * @param array $data
- * @return void
- */
- public function update($data): void
- {
- // If there's no id to update, don't update
- if ( ! array_key_exists('hummingbird_id', $data))
- {
- return;
- }
-
- $id = $data['hummingbird_id'];
- unset($data['hummingbird_id']);
-
- $this->db->set($data)
- ->where('hummingbird_id', $id)
- ->update('manga_set');
- }
-
- /**
- * Remove a collection item
- *
- * @param array $data
- * @return void
- */
- public function delete($data): void
- {
- // If there's no id to update, don't delete
- if ( ! array_key_exists('hummingbird_id', $data))
- {
- return;
- }
-
- $this->db->where('hummingbird_id', $data['hummingbird_id'])
- ->delete('genre_manga_set_link');
-
- $this->db->where('hummingbird_id', $data['hummingbird_id'])
- ->delete('manga_set');
- }
-
- /**
- * Get the details of a collection item
- *
- * @param string $kitsuId
- * @return array
- */
- public function get($kitsuId): array
- {
- $query = $this->db->from('manga_set')
- ->where('hummingbird_id', $kitsuId)
- ->get();
-
- return $query->fetch(PDO::FETCH_ASSOC);
- }
-
- /**
- * Update genre information for selected manga
- *
- * @param string $mangaId The current manga
- * @return void
- */
- private function updateGenre($mangaId): void
- {
- $genreInfo = $this->getGenreData();
- $genres = $genreInfo['genres'];
- $links = $genreInfo['links'];
-
- // Get api information
- $manga = $this->mangaModel->getMangaById($mangaId);
-
- foreach ($manga['genres'] as $genre)
- {
- // Add genres that don't currently exist
- if ( ! \in_array($genre, $genres, TRUE))
- {
- $this->db->set('genre', $genre)
- ->insert('genres');
-
- $genres[] = $genre;
- }
-
- // Update link table
- // Get id of genre to put in link table
- $flippedGenres = array_flip($genres);
-
- $insertArray = [
- 'hummingbird_id' => $mangaId,
- 'genre_id' => $flippedGenres[$genre]
- ];
-
- if (array_key_exists($mangaId, $links))
- {
- if ( ! \in_array($flippedGenres[$genre], $links[$mangaId], TRUE))
- {
- $this->db->set($insertArray)->insert('genre_manga_set_link');
- }
- }
- else
- {
- $this->db->set($insertArray)->insert('genre_manga_set_link');
- }
- }
- }
-
- /**
- * Get list of existing genres
- *
- * @return array
- */
- private function getGenreData(): array
- {
- $genres = [];
- $links = [];
-
- // Get existing genres
- $query = $this->db->select('id, genre')
- ->from('genres')
- ->get();
- foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $genre)
- {
- $genres[$genre['id']] = $genre['genre'];
- }
-
- // Get existing link table entries
- $query = $this->db->select('hummingbird_id, genre_id')
- ->from('genre_manga_set_link')
- ->get();
- foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $link)
- {
- if (array_key_exists($link['hummingbird_id'], $links))
- {
- $links[$link['hummingbird_id']][] = $link['genre_id'];
- }
- else
- {
- $links[$link['hummingbird_id']] = [$link['genre_id']];
- }
- }
-
- return [
- 'genres' => $genres,
- 'links' => $links
- ];
- }
}
// End of MangaCollectionModel.php
\ No newline at end of file
diff --git a/src/Types/AbstractType.php b/src/Types/AbstractType.php
index 6f66eb93..e12aae00 100644
--- a/src/Types/AbstractType.php
+++ b/src/Types/AbstractType.php
@@ -179,7 +179,7 @@ abstract class AbstractType implements ArrayAccess, Countable {
/**
* Recursively cast properties to an array
*
- * @param null $parent
+ * @param mixed $parent
* @return mixed
*/
public function toArray($parent = null)
diff --git a/src/Types/Anime.php b/src/Types/Anime.php
index f49af8e4..9b2b517d 100644
--- a/src/Types/Anime.php
+++ b/src/Types/Anime.php
@@ -38,12 +38,12 @@ class Anime extends AbstractType {
public $cover_image;
/**
- * @var string|number
+ * @var string|int
*/
public $episode_count;
/**
- * @var string|number
+ * @var string|int
*/
public $episode_length;
diff --git a/src/Types/AnimeListItem.php b/src/Types/AnimeListItem.php
index 4449ab84..ece92c86 100644
--- a/src/Types/AnimeListItem.php
+++ b/src/Types/AnimeListItem.php
@@ -74,12 +74,12 @@ final class AnimeListItem extends AbstractType {
public $rewatching;
/**
- * @var number
+ * @var int
*/
public $rewatched;
/**
- * @var number
+ * @var int
*/
public $user_rating;
diff --git a/src/Types/Character.php b/src/Types/Character.php
index 906d58cc..a97dd974 100644
--- a/src/Types/Character.php
+++ b/src/Types/Character.php
@@ -41,7 +41,7 @@ final class Character extends AbstractType {
public $included;
/**
- * @var array
+ * @var Media
*/
public $media;
@@ -62,9 +62,6 @@ final class Character extends AbstractType {
public function setMedia ($media): void
{
- $this->media = new class($media) extends AbstractType {
- public $anime;
- public $manga;
- };
+ $this->media = new Media($media);
}
}
\ No newline at end of file
diff --git a/src/Types/Characters.php b/src/Types/Characters.php
new file mode 100644
index 00000000..390549ed
--- /dev/null
+++ b/src/Types/Characters.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2015 - 2019 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.2
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Types;
+
+final class Characters extends AbstractType {
+ /**
+ * @var array
+ */
+ public $main;
+
+ /**
+ * @var array
+ */
+ public $supporting;
+}
\ No newline at end of file
diff --git a/src/Types/Config/Database.php b/src/Types/Config/Database.php
index 3f761ead..ddf97de1 100644
--- a/src/Types/Config/Database.php
+++ b/src/Types/Config/Database.php
@@ -40,7 +40,7 @@ class Database extends AbstractType {
public $pass;
/**
- * @var string|number
+ * @var string|int
*/
public $port;
diff --git a/src/Types/Media.php b/src/Types/Media.php
new file mode 100644
index 00000000..241de436
--- /dev/null
+++ b/src/Types/Media.php
@@ -0,0 +1,29 @@
+
+ * @copyright 2015 - 2019 Timothy J. Warren
+ * @license http://www.opensource.org/licenses/mit-license.html MIT License
+ * @version 4.2
+ * @link https://git.timshomepage.net/timw4mail/HummingBirdAnimeClient
+ */
+
+namespace Aviat\AnimeClient\Types;
+
+final class Media extends AbstractType {
+ /**
+ * @var array
+ */
+ public $anime = [];
+
+ /**
+ * @var array
+ */
+ public $manga = [];
+}
\ No newline at end of file
diff --git a/src/Types/Person.php b/src/Types/Person.php
index 71984222..b1baac67 100644
--- a/src/Types/Person.php
+++ b/src/Types/Person.php
@@ -31,7 +31,7 @@ final class Person extends AbstractType {
public $name;
/**
- * @var object
+ * @var Characters
*/
public $characters;
@@ -42,9 +42,6 @@ final class Person extends AbstractType {
public function setCharacters($characters): void
{
- $this->characters = new class($characters) extends AbstractType {
- public $main;
- public $supporting;
- };
+ $this->characters = new Characters($characters);
}
}
\ No newline at end of file