diff --git a/migrations/20200430175135_anime_collection_cleanup.php b/migrations/20200430175135_anime_collection_cleanup.php new file mode 100644 index 00000000..0f4c5330 --- /dev/null +++ b/migrations/20200430175135_anime_collection_cleanup.php @@ -0,0 +1,26 @@ +hasTable('genre_anime_set_link')) + { + $this->table('genre_anime_set_link') + ->rename('anime_set_genre_link') + ->update(); + } + } + + public function down() + { + if ($this->hasTable('anime_set_genre_link')) + { + $this->table('anime_set_genre_link') + ->rename('genre_anime_set_link') + ->update(); + } + } +} diff --git a/src/AnimeClient/AnimeClient.php b/src/AnimeClient/AnimeClient.php index f06fb00f..4fca5075 100644 --- a/src/AnimeClient/AnimeClient.php +++ b/src/AnimeClient/AnimeClient.php @@ -332,4 +332,17 @@ function createPlaceholderImage ($path, ?int $width, ?int $height, $text = 'Imag imagewebp($pngImage, $path . '/placeholder.webp'); imagedestroy($pngImage); +} + +/** + * Check that there is a value for at least one item in a collection with the specified key + * + * @param array $search + * @param string $key + * @return bool + */ +function col_not_empty(array $search, string $key): bool +{ + $items = array_filter(array_column($search, $key), fn ($x) => ( ! empty($x))); + return count($items) > 0; } \ No newline at end of file diff --git a/src/AnimeClient/Controller/AnimeCollection.php b/src/AnimeClient/Controller/AnimeCollection.php index 3ef9687c..96f4bafe 100644 --- a/src/AnimeClient/Controller/AnimeCollection.php +++ b/src/AnimeClient/Controller/AnimeCollection.php @@ -101,12 +101,10 @@ final class AnimeCollection extends BaseController { 'list' => 'list' ]; - $data = $this->animeCollectionModel->getCollection(); - $this->outputHTML('collection/' . $viewMap[$view], [ 'title' => $this->config->get('whose_list') . "'s Anime Collection", - 'sections' => $data, - 'genres' => $this->animeCollectionModel->getGenreList() + 'sections' => $this->animeCollectionModel->getCollection(), + 'all' => $this->animeCollectionModel->getFlatCollection(), ]); } @@ -233,6 +231,13 @@ final class AnimeCollection extends BaseController { $this->redirect('/anime-collection/view', 303); } + /** + * Update a collection item + * + * @param $data + * @throws ContainerException + * @throws NotFoundException + */ protected function update($data): void { if (array_key_exists('hummingbird_id', $data)) diff --git a/src/AnimeClient/Model/AnimeCollection.php b/src/AnimeClient/Model/AnimeCollection.php index a15af25a..42e50251 100644 --- a/src/AnimeClient/Model/AnimeCollection.php +++ b/src/AnimeClient/Model/AnimeCollection.php @@ -69,6 +69,47 @@ final class AnimeCollection extends Collection { return $collection; } + /** + * Get the collection from the database + * + * @return array + */ + public function getFlatCollection(): array + { + if ( ! $this->validDatabase) + { + return []; + } + + $query = $this->db->select('a.hummingbird_id, slug, title, alternate_title, show_type, + age_rating, episode_count, episode_length, cover_image, notes') + ->from('anime_set a') + ->orderBy('title') + ->get(); + + // Add genres associated with each item + $rows = $query->fetchAll(PDO::FETCH_ASSOC); + $genres = $this->getGenreList(); + $media = $this->getMediaList(); + + foreach($rows as &$row) + { + $id = $row['hummingbird_id']; + + $row['genres'] = array_key_exists($id, $genres) + ? $genres[$id] + : []; + + $row['media'] = array_key_exists($id, $media) + ? $media[$id] + : []; + + sort($row['genres']); + } + + return $rows; + } + /** * Get list of media types * @@ -262,7 +303,7 @@ final class AnimeCollection extends Collection { $this->db->beginTransaction(); $this->db->where('hummingbird_id', $data['hummingbird_id']) - ->delete('genre_anime_set_link'); + ->delete('anime_set_genre_link'); $this->db->where('hummingbird_id', $data['hummingbird_id']) ->delete('anime_set_media_link'); @@ -361,7 +402,7 @@ final class AnimeCollection extends Collection { try { $this->db->select('hummingbird_id, genre') - ->from('genre_anime_set_link gl') + ->from('anime_set_genre_link gl') ->join('genres g', 'g.id=gl.genre_id', 'left'); @@ -402,6 +443,68 @@ final class AnimeCollection extends Collection { return $output; } + /** + * Get media for anime collection items + * + * @param array $filter + * @return array + */ + public function getMediaList(array $filter = []): array + { + if ($this->validDatabase === FALSE) + { + return []; + } + + $output = []; + + // Catch the missing table PDOException + // so that the collection does not show an + // error by default + try + { + $this->db->select('m.type as media, hummingbird_id') + ->from('anime_set_media_link ml') + ->join('media m', 'm.id=ml.media_id', 'left'); + + + if ( ! empty($filter)) + { + $this->db->whereIn('hummingbird_id', $filter); + } + + $query = $this->db->orderBy('hummingbird_id') + ->orderBy('media') + ->get(); + + foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $row) + { + $id = $row['hummingbird_id']; + $media = $row['media']; + + // Empty genre names aren't useful + if (empty($media)) + { + continue; + } + + if (array_key_exists($id, $output)) + { + $output[$id][] = $media; + } + else + { + $output[$id] = [$media]; + } + } + } + catch (PDOException $e) {} + + $this->db->resetQuery(); + + return $output; + } + private function updateMediaLink(string $animeId, array $media): void { $this->db->beginTransaction(); @@ -469,7 +572,11 @@ final class AnimeCollection extends Collection { if ( ! empty($linksToInsert)) { - $this->db->insertBatch('genre_anime_set_link', $linksToInsert); + try + { + $this->db->insertBatch('anime_set_genre_link', $linksToInsert); + } + catch (PDOException $e) {} } } @@ -554,7 +661,7 @@ final class AnimeCollection extends Collection { $links = []; $query = $this->db->select('hummingbird_id, genre_id') - ->from('genre_anime_set_link') + ->from('anime_set_genre_link') ->get(); foreach ($query->fetchAll(PDO::FETCH_ASSOC) as $link) diff --git a/src/AnimeClient/Types/Config.php b/src/AnimeClient/Types/Config.php index b311e0d4..53546c49 100644 --- a/src/AnimeClient/Types/Config.php +++ b/src/AnimeClient/Types/Config.php @@ -98,12 +98,12 @@ class Config extends AbstractType { /** * @var bool */ - public bool $show_anime_collection = FALSE; + public $show_anime_collection = FALSE; /** * @var bool */ - public bool $show_manga_collection = FALSE; + public $show_manga_collection = FALSE; /** * CSS theme: light, dark, or auto-switching diff --git a/src/AnimeClient/Types/FormItem.php b/src/AnimeClient/Types/FormItem.php index 893dd858..139d6309 100644 --- a/src/AnimeClient/Types/FormItem.php +++ b/src/AnimeClient/Types/FormItem.php @@ -21,7 +21,7 @@ namespace Aviat\AnimeClient\Types; */ class FormItem extends AbstractType { /** - * @var string + * @var string|int */ public $id; @@ -31,9 +31,9 @@ class FormItem extends AbstractType { public ?string $anilist_item_id; /** - * @var string + * @var string|int */ - public ?string $mal_id; + public $mal_id; /** * @var FormItemData