From 2f657dc20b4aa79b6fb231444d5c81dfbefe01b2 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Thu, 16 Mar 2023 13:04:55 -0400 Subject: [PATCH] Add Routing attributes to controllers for a potential future refactoring --- src/AnimeClient/Controller.php | 14 +-- src/AnimeClient/Controller/Anime.php | 24 +++-- .../Controller/AnimeCollection.php | 15 ++- src/AnimeClient/Controller/Character.php | 4 + src/AnimeClient/Controller/History.php | 4 + src/AnimeClient/Controller/Images.php | 4 + src/AnimeClient/Controller/Manga.php | 47 ++++------ src/AnimeClient/Controller/Misc.php | 92 +++++++++++++++++++ src/AnimeClient/Controller/People.php | 4 + src/AnimeClient/Controller/Settings.php | 7 ++ src/AnimeClient/Controller/User.php | 5 + 11 files changed, 172 insertions(+), 48 deletions(-) diff --git a/src/AnimeClient/Controller.php b/src/AnimeClient/Controller.php index 72ae531e..b0beb7e0 100644 --- a/src/AnimeClient/Controller.php +++ b/src/AnimeClient/Controller.php @@ -340,7 +340,7 @@ class Controller * Output a template to HTML, using the provided data * * @codeCoverageIgnore - *@throws InvalidArgumentException + * @throws InvalidArgumentException */ protected function outputHTML(string $template, array $data = [], ?HtmlView $view = NULL, int $code = 200): void { @@ -362,7 +362,7 @@ class Controller */ protected function outputJSON(mixed $data, int $code): void { - (new JsonView()) + JsonView::new() ->setOutput($data) ->setStatusCode($code) ->send(); @@ -375,13 +375,9 @@ class Controller */ protected function redirect(string $url, int $code): void { - try - { - (new HttpView())->redirect($url, $code)->send(); - } - catch (\Throwable) - { - } + HttpView::new() + ->redirect($url, $code) + ->send(); } } diff --git a/src/AnimeClient/Controller/Anime.php b/src/AnimeClient/Controller/Anime.php index 352623c1..a29e1abd 100644 --- a/src/AnimeClient/Controller/Anime.php +++ b/src/AnimeClient/Controller/Anime.php @@ -21,6 +21,8 @@ use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus; use Aviat\AnimeClient\Controller as BaseController; use Aviat\AnimeClient\Model\Anime as AnimeModel; use Aviat\AnimeClient\Types\FormItem; +use Aviat\Ion\Attribute\Controller; +use Aviat\Ion\Attribute\Route; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; use Aviat\Ion\Json; @@ -32,6 +34,7 @@ use TypeError; /** * Controller for Anime-related pages */ +#[Controller('anime')] final class Anime extends BaseController { /** @@ -66,6 +69,7 @@ final class Anime extends BaseController * @throws InvalidArgumentException * @throws Throwable */ + #[Route('anime.list', '/anime/{status}{/view}')] public function index(int|string $status = KitsuWatchingStatus::WATCHING, ?string $view = NULL): void { if ( ! in_array($status, [ @@ -111,6 +115,7 @@ final class Anime extends BaseController * @throws RouteNotFound * @throws Throwable */ + #[Route('anime.add.get', '/anime/add')] public function addForm(): void { $this->checkAuth(); @@ -131,6 +136,7 @@ final class Anime extends BaseController * * @throws Throwable */ + #[Route('anime.add.post', '/anime/add', Route::POST)] public function add(): void { $this->checkAuth(); @@ -165,6 +171,7 @@ final class Anime extends BaseController /** * Form to edit details about a series */ + #[Route('anime.edit', '/anime/edit/{id}/{status}')] public function edit(string $id, string $status = 'all'): void { $this->checkAuth(); @@ -188,6 +195,7 @@ final class Anime extends BaseController /** * Search for anime */ + #[Route('anime.search', '/anime/search')] public function search(): void { $queryParams = $this->request->getQueryParams(); @@ -200,6 +208,7 @@ final class Anime extends BaseController * * @throws Throwable */ + #[Route('anime.update.post', '/anime/update_form', Route::POST)] public function formUpdate(): void { $this->checkAuth(); @@ -230,18 +239,14 @@ final class Anime extends BaseController * * @throws Throwable */ + #[Route('anime.increment', '/anime/increment', Route::POST)] public function increment(): void { $this->checkAuth(); - if (str_contains($this->request->getHeader('content-type')[0], 'application/json')) - { - $data = Json::decode((string) $this->request->getBody()); - } - else - { - $data = (array) $this->request->getParsedBody(); - } + $data = str_contains($this->request->getHeader('content-type')[0], 'application/json') + ? Json::decode((string) $this->request->getBody()) + : (array) $this->request->getParsedBody(); if (empty($data)) { @@ -261,6 +266,7 @@ final class Anime extends BaseController * * @throws Throwable */ + #[Route('anime.delete', '/anime/delete', Route::POST)] public function delete(): void { $this->checkAuth(); @@ -286,6 +292,7 @@ final class Anime extends BaseController * * @throws InvalidArgumentException */ + #[Route('anime.details', '/anime/details/{id}')] public function details(string $id): void { try @@ -324,6 +331,7 @@ final class Anime extends BaseController } } + #[Route('anime.random', '/anime/details/random')] public function random(): void { try diff --git a/src/AnimeClient/Controller/AnimeCollection.php b/src/AnimeClient/Controller/AnimeCollection.php index d1668bfc..5577eda9 100644 --- a/src/AnimeClient/Controller/AnimeCollection.php +++ b/src/AnimeClient/Controller/AnimeCollection.php @@ -20,8 +20,11 @@ use Aviat\AnimeClient\Model\{ Anime as AnimeModel, AnimeCollection as AnimeCollectionModel }; +use Aviat\Ion\Attribute\Controller; +use Aviat\Ion\Attribute\Route; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; +use Aviat\Ion\Json; use Aviat\Ion\Exception\DoubleRenderException; use InvalidArgumentException; @@ -29,6 +32,7 @@ use InvalidArgumentException; /** * Controller for Anime collection pages */ +#[Controller('anime.collection')] final class AnimeCollection extends BaseController { /** @@ -61,6 +65,8 @@ final class AnimeCollection extends BaseController ]); } + #[Route('anime.collection.redirect', '/anime-collection')] + #[Route('anime.collection.redirect2', '/anime-collection/')] public function index(): void { $this->redirect('/anime-collection/view', 303); @@ -71,6 +77,7 @@ final class AnimeCollection extends BaseController * * @throws DoubleRenderException */ + #[Route('anime.collection.search', '/anime-collection/search')] public function search(): void { $queryParams = $this->request->getQueryParams(); @@ -85,6 +92,7 @@ final class AnimeCollection extends BaseController * @throws InvalidArgumentException * @throws NotFoundException */ + #[Route('anime.collection.view', '/anime-collection/view{/view}')] public function view(?string $view = ''): void { $viewMap = [ @@ -112,7 +120,9 @@ final class AnimeCollection extends BaseController * @throws NotFoundException * @throws RouteNotFound */ - public function form($id = NULL): void + #[Route('anime.collection.add.get', '/anime-collection/add')] + #[Route('anime.collection.edit.get', '/anime-collection/edit/{id}')] + public function form(?int $id = NULL): void { $this->checkAuth(); @@ -140,6 +150,7 @@ final class AnimeCollection extends BaseController * @throws InvalidArgumentException * @throws NotFoundException */ + #[Route('anime.collection.edit.post', '/anime-collection/edit', Route::POST)] public function edit(): void { $this->checkAuth(); @@ -153,6 +164,7 @@ final class AnimeCollection extends BaseController * @throws InvalidArgumentException * @throws NotFoundException */ + #[Route('anime.collection.add.post', '/anime-collection/add', Route::POST)] public function add(): void { $this->checkAuth(); @@ -202,6 +214,7 @@ final class AnimeCollection extends BaseController /** * Remove a collection item */ + #[Route('anime.collection.delete', '/anime-collection/delete', Route::POST)] public function delete(): void { $this->checkAuth(); diff --git a/src/AnimeClient/Controller/Character.php b/src/AnimeClient/Controller/Character.php index 0948f2a7..1bb5466e 100644 --- a/src/AnimeClient/Controller/Character.php +++ b/src/AnimeClient/Controller/Character.php @@ -18,12 +18,15 @@ use Aviat\AnimeClient\API\Kitsu\Model; use Aviat\AnimeClient\API\Kitsu\Transformer\CharacterTransformer; use Aviat\AnimeClient\Controller as BaseController; +use Aviat\Ion\Attribute\Controller; +use Aviat\Ion\Attribute\Route; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; /** * Controller for character description pages */ +#[Controller] final class Character extends BaseController { private Model $model; @@ -43,6 +46,7 @@ final class Character extends BaseController /** * Show information about a character */ + #[Route('character', '/character/{slug}')] public function index(string $slug): void { $rawData = $this->model->getCharacter($slug); diff --git a/src/AnimeClient/Controller/History.php b/src/AnimeClient/Controller/History.php index 8bbe89ab..9f654ea4 100644 --- a/src/AnimeClient/Controller/History.php +++ b/src/AnimeClient/Controller/History.php @@ -14,6 +14,8 @@ namespace Aviat\AnimeClient\Controller; +use Aviat\Ion\Attribute\Controller; +use Aviat\Ion\Attribute\Route; use Aviat\AnimeClient\{Controller as BaseController, Model}; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; @@ -21,6 +23,7 @@ use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; /** * Controller for Anime-related pages */ +#[Controller] final class History extends BaseController { /** @@ -47,6 +50,7 @@ final class History extends BaseController $this->mangaModel = $container->get('manga-model'); } + #[Route('history', '/history/{type}')] public function index(string $type = 'anime'): void { if (method_exists($this, $type)) diff --git a/src/AnimeClient/Controller/Images.php b/src/AnimeClient/Controller/Images.php index f8eb290f..20c9eccd 100644 --- a/src/AnimeClient/Controller/Images.php +++ b/src/AnimeClient/Controller/Images.php @@ -15,6 +15,8 @@ namespace Aviat\AnimeClient\Controller; use Aviat\AnimeClient\Controller as BaseController; +use Aviat\Ion\Attribute\Controller; +use Aviat\Ion\Attribute\Route; use Throwable; use function Amp\Promise\wait; use function Aviat\AnimeClient\{createPlaceholderImage, getResponse}; @@ -25,6 +27,7 @@ use function in_array; /** * Controller for handling routes that don't fit elsewhere */ +#[Controller] final class Images extends BaseController { /** @@ -35,6 +38,7 @@ final class Images extends BaseController * @param bool $display Whether to output the image to the server * @throws Throwable */ + #[Route('image_proxy', '/public/images/{type}/{file}')] public function cache(string $type, string $file, bool $display = TRUE): void { $currentUrl = (string) $this->request->getUri(); diff --git a/src/AnimeClient/Controller/Manga.php b/src/AnimeClient/Controller/Manga.php index a0d091f4..5ab92bc2 100644 --- a/src/AnimeClient/Controller/Manga.php +++ b/src/AnimeClient/Controller/Manga.php @@ -17,9 +17,11 @@ namespace Aviat\AnimeClient\Controller; use Aura\Router\Exception\RouteNotFound; use Aviat\AnimeClient\API\Kitsu\Transformer\MangaListTransformer; use Aviat\AnimeClient\API\Mapping\MangaReadingStatus; -use Aviat\AnimeClient\Controller; +use Aviat\AnimeClient\Controller as BaseController; use Aviat\AnimeClient\Model\Manga as MangaModel; use Aviat\AnimeClient\Types\FormItem; +use Aviat\Ion\Attribute\Controller; +use Aviat\Ion\Attribute\Route; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; use Aviat\Ion\Json; @@ -30,7 +32,8 @@ use Throwable; /** * Controller for manga list */ -final class Manga extends Controller +#[Controller('manga')] +final class Manga extends BaseController { /** * The manga model @@ -57,10 +60,8 @@ final class Manga extends Controller /** * Get a section of the manga list - * - * @param string $view - *@throws InvalidArgumentException */ + #[Route('manga.list', '/list/{status}{/view}')] public function index(string $status = 'all', ?string $view = ''): void { if ( ! in_array($status, [ @@ -98,13 +99,9 @@ final class Manga extends Controller } /** - * Form to add an manga - * - * @throws ContainerException - * @throws InvalidArgumentException - * @throws NotFoundException - * @throws RouteNotFound + * Form to add a manga */ + #[Route('manga.add.get', '/manga/add')] public function addForm(): void { $this->checkAuth(); @@ -123,10 +120,9 @@ final class Manga extends Controller } /** - * Add an manga to the list - * - * @throws Throwable + * Add a manga to the list */ + #[Route('manage.add.post', '/manga/add', Route::POST)] public function add(): void { $this->checkAuth(); @@ -159,12 +155,8 @@ final class Manga extends Controller /** * Show the manga edit form - * - * @throws ContainerException - * @throws InvalidArgumentException - * @throws NotFoundException - * @throws RouteNotFound */ + #[Route('manga.edit', '/manga/edit/{id}/{status}')] public function edit(string $id, string $status = 'All'): void { $this->checkAuth(); @@ -189,6 +181,7 @@ final class Manga extends Controller /** * Search for a manga to add to the list */ + #[Route('manga.search', '/manga/search')] public function search(): void { $queryParams = $this->request->getQueryParams(); @@ -198,9 +191,8 @@ final class Manga extends Controller /** * Update an manga item via a form submission - * - * @throws Throwable */ + #[Route('manga.update.post', '/manga/update', Route::POST)] public function formUpdate(): void { $this->checkAuth(); @@ -228,8 +220,8 @@ final class Manga extends Controller /** * Increment the progress of a manga item - * @throws Throwable */ + #[Route('manga.increment', '/manga/increment', Route::POST)] public function increment(): void { $this->checkAuth(); @@ -253,9 +245,8 @@ final class Manga extends Controller /** * Remove an manga from the list - * - * @throws Throwable */ + #[Route('manga.delete', '/manga/delete', Route::POST)] public function delete(): void { $this->checkAuth(); @@ -278,10 +269,8 @@ final class Manga extends Controller /** * View details of an manga - * - * @throws InvalidArgumentException - * @throws Throwable */ + #[Route('manga.details', '/manga/details/{id}')] public function details(string $id): void { $data = $this->model->getManga($id); @@ -309,10 +298,8 @@ final class Manga extends Controller /** * View details of a random manga - * - * @throws InvalidArgumentException - * @throws Throwable */ + #[Route('manga.random', '/manga/details/random')] public function random(): void { $data = $this->model->getRandomManga(); diff --git a/src/AnimeClient/Controller/Misc.php b/src/AnimeClient/Controller/Misc.php index 0bc16f9a..1f4ac47d 100644 --- a/src/AnimeClient/Controller/Misc.php +++ b/src/AnimeClient/Controller/Misc.php @@ -14,19 +14,44 @@ namespace Aviat\AnimeClient\Controller; +use Aviat\AnimeClient\API\Kitsu\Model; +use Aviat\AnimeClient\API\Kitsu\Transformer\CharacterTransformer; +use Aviat\AnimeClient\API\Kitsu\Transformer\PersonTransformer; use Aviat\AnimeClient\Controller as BaseController; use Aviat\AnimeClient\Enum\EventType; +use Aviat\Ion\Attribute\DefaultController; +use Aviat\Ion\Attribute\Route; +use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Event; use Aviat\Ion\View\HtmlView; /** * Controller for handling routes that don't fit elsewhere */ +#[DefaultController] final class Misc extends BaseController { + private Model $model; + + public function __construct(ContainerInterface $container) + { + parent::__construct($container); + $this->model = $container->get('kitsu-model'); + } + + /** + * Redirect to the default controller/url from an empty path + */ + #[Route('index_redirect', '/')] + public function index(): void + { + parent::redirectToDefaultRoute(); + } + /** * Purges the API cache */ + #[Route('cache_purge', '/cache_purge')] public function clearCache(): void { $this->checkAuth(); @@ -41,6 +66,7 @@ final class Misc extends BaseController /** * Show the login form */ + #[Route('login', '/login')] public function login(string $status = ''): void { $message = ''; @@ -64,6 +90,7 @@ final class Misc extends BaseController /** * Attempt login authentication */ + #[Route('login.post', '/login', Route::POST)] public function loginAction(): void { $post = (array) $this->request->getParsedBody(); @@ -86,6 +113,7 @@ final class Misc extends BaseController /** * Deauthorize the current user */ + #[Route('logout', '/logout')] public function logout(): void { $this->auth->logout(); @@ -96,8 +124,72 @@ final class Misc extends BaseController /** * Check if the current user is logged in */ + #[Route('heartbeat', '/heartbeat')] public function heartbeat(): void { $this->outputJSON(['hasAuth' => $this->auth->isAuthenticated()], 200); } + + /** + * Show information about a character + */ + #[Route('character', '/character/{slug}')] + public function character(string $slug): void + { + $rawData = $this->model->getCharacter($slug); + + if (( ! array_key_exists('data', $rawData)) || empty($rawData['data'])) + { + $this->notFound( + $this->formatTitle( + 'Characters', + 'Character not found' + ), + 'Character Not Found' + ); + + return; + } + + $data = (new CharacterTransformer())->transform($rawData)->toArray(); + + $this->outputHTML('character/details', [ + 'title' => $this->formatTitle( + 'Characters', + $data['name'] + ), + 'data' => $data, + ]); + } + + /** + * Show information about a person + */ + #[Route('person', '/people/{slug}')] + public function person(string $slug): void + { + $rawData = $this->model->getPerson($slug); + $data = (new PersonTransformer())->transform($rawData)->toArray(); + + if (( ! array_key_exists('data', $rawData)) || empty($rawData['data'])) + { + $this->notFound( + $this->formatTitle( + 'People', + 'Person not found' + ), + 'Person Not Found' + ); + + return; + } + + $this->outputHTML('person/details', [ + 'title' => $this->formatTitle( + 'People', + $data['name'] + ), + 'data' => $data, + ]); + } } diff --git a/src/AnimeClient/Controller/People.php b/src/AnimeClient/Controller/People.php index ee7f115f..e142c0e6 100644 --- a/src/AnimeClient/Controller/People.php +++ b/src/AnimeClient/Controller/People.php @@ -18,12 +18,15 @@ use Aviat\AnimeClient\API\Kitsu\Model; use Aviat\AnimeClient\API\Kitsu\Transformer\PersonTransformer; use Aviat\AnimeClient\Controller as BaseController; +use Aviat\Ion\Attribute\Controller; +use Aviat\Ion\Attribute\Route; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; /** * Controller for People pages */ +#[Controller] final class People extends BaseController { private Model $model; @@ -43,6 +46,7 @@ final class People extends BaseController /** * Show information about a person */ + #[Route('person', '/people/{slug}')] public function index(string $slug): void { $rawData = $this->model->getPerson($slug); diff --git a/src/AnimeClient/Controller/Settings.php b/src/AnimeClient/Controller/Settings.php index fd4e51ef..325f0861 100644 --- a/src/AnimeClient/Controller/Settings.php +++ b/src/AnimeClient/Controller/Settings.php @@ -18,12 +18,15 @@ use Aura\Router\Exception\RouteNotFound; use Aviat\AnimeClient\API\Anilist\Model as AnilistModel; use Aviat\AnimeClient\Controller as BaseController; use Aviat\AnimeClient\Model\Settings as SettingsModel; +use Aviat\Ion\Attribute\Controller; +use Aviat\Ion\Attribute\Route; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; /** * Controller for user settings */ +#[Controller] final class Settings extends BaseController { private AnilistModel $anilistModel; @@ -49,6 +52,7 @@ final class Settings extends BaseController /** * Show the user settings, if logged in */ + #[Route('settings', '/settings')] public function index(): void { $auth = $this->container->get('auth'); @@ -71,6 +75,7 @@ final class Settings extends BaseController * * @throws RouteNotFound */ + #[Route('settings-post', '/settings/update', Route::POST)] public function update(): void { $post = (array) $this->request->getParsedBody(); @@ -91,6 +96,7 @@ final class Settings extends BaseController /** * Redirect to Anilist to start Oauth flow */ + #[Route('anilist-redirect', '/anilist-redirect')] public function anilistRedirect(): void { $query = http_build_query([ @@ -107,6 +113,7 @@ final class Settings extends BaseController /** * Oauth callback for Anilist API */ + #[Route('anilist-callback', '/anilist-oauth')] public function anilistCallback(): void { $query = $this->request->getQueryParams(); diff --git a/src/AnimeClient/Controller/User.php b/src/AnimeClient/Controller/User.php index 316824a4..3bc6ad20 100644 --- a/src/AnimeClient/Controller/User.php +++ b/src/AnimeClient/Controller/User.php @@ -18,12 +18,15 @@ use Aviat\AnimeClient\API\Kitsu\Model; use Aviat\AnimeClient\API\Kitsu\Transformer\UserTransformer; use Aviat\AnimeClient\Controller as BaseController; +use Aviat\Ion\Attribute\Controller; +use Aviat\Ion\Attribute\Route; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; /** * Controller for handling routes that don't fit elsewhere */ +#[Controller] final class User extends BaseController { private Model $kitsuModel; @@ -44,6 +47,7 @@ final class User extends BaseController /** * Show the user profile page for the configured user */ + #[Route('default_user_info', '/me')] public function me(): void { $this->about('me'); @@ -52,6 +56,7 @@ final class User extends BaseController /** * Show the user profile page */ + #[Route('user_info', '/user/{username}')] public function about(string $username): void { $isMainUser = $username === 'me';