diff --git a/app/CarbonDateRange.php b/app/CarbonDateRange.php index 1b90903..70f31b5 100644 --- a/app/CarbonDateRange.php +++ b/app/CarbonDateRange.php @@ -12,8 +12,8 @@ use Jikan\Model\Common\DateProp; */ class CarbonDateRange { - private ?Carbon $fromObj; - private ?Carbon $untilObj; + private ?Carbon $fromObj = null; + private ?Carbon $untilObj = null; public function __construct(?Carbon $from, ?Carbon $to) { diff --git a/app/Concerns/HasRequestFingerprint.php b/app/Concerns/HasRequestFingerprint.php index 23d4bb3..017cd5e 100644 --- a/app/Concerns/HasRequestFingerprint.php +++ b/app/Concerns/HasRequestFingerprint.php @@ -13,7 +13,7 @@ use Spatie\LaravelData\Resolvers\DataFromSomethingResolver; */ trait HasRequestFingerprint { - protected ?string $fingerprint; + protected ?string $fingerprint = null; public static function fromRequest(Request $request): ?static { diff --git a/app/Contracts/AnimeRepository.php b/app/Contracts/AnimeRepository.php index 18674f3..344c151 100644 --- a/app/Contracts/AnimeRepository.php +++ b/app/Contracts/AnimeRepository.php @@ -7,7 +7,7 @@ use App\Enums\AnimeScheduleFilterEnum; use App\Enums\AnimeTypeEnum; use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder; use Illuminate\Support\Carbon; -use \Laravel\Scout\Builder as ScoutBuilder; +use Laravel\Scout\Builder as ScoutBuilder; /** * @implements Repository diff --git a/app/Contracts/CharacterRepository.php b/app/Contracts/CharacterRepository.php index 11540d0..e0761b1 100644 --- a/app/Contracts/CharacterRepository.php +++ b/app/Contracts/CharacterRepository.php @@ -3,8 +3,8 @@ namespace App\Contracts; use App\Character; -use \Illuminate\Database\Eloquent\Builder as EloquentBuilder; -use \Laravel\Scout\Builder as ScoutBuilder; +use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder; +use Laravel\Scout\Builder as ScoutBuilder; /** * @implements Repository diff --git a/app/Contracts/PeopleRepository.php b/app/Contracts/PeopleRepository.php index d1dfec2..a4eab49 100644 --- a/app/Contracts/PeopleRepository.php +++ b/app/Contracts/PeopleRepository.php @@ -3,8 +3,8 @@ namespace App\Contracts; use App\Person; -use \Illuminate\Database\Eloquent\Builder as EloquentBuilder; -use \Laravel\Scout\Builder as ScoutBuilder; +use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder; +use Laravel\Scout\Builder as ScoutBuilder; /** * @implements Repository diff --git a/app/Dto/AnimeForumLookupCommand.php b/app/Dto/AnimeForumLookupCommand.php index f1e1b89..db8f887 100644 --- a/app/Dto/AnimeForumLookupCommand.php +++ b/app/Dto/AnimeForumLookupCommand.php @@ -5,9 +5,9 @@ namespace App\Dto; use App\Casts\EnumCast; use App\Enums\AnimeForumFilterEnum; use Illuminate\Http\JsonResponse; -use Illuminate\Support\Optional; use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\WithCast; +use Spatie\LaravelData\Optional; /** * @extends LookupDataCommand diff --git a/app/Dto/AnimeVideosEpisodesLookupCommand.php b/app/Dto/AnimeVideosEpisodesLookupCommand.php index 1ca2331..db57445 100644 --- a/app/Dto/AnimeVideosEpisodesLookupCommand.php +++ b/app/Dto/AnimeVideosEpisodesLookupCommand.php @@ -3,9 +3,9 @@ namespace App\Dto; use Illuminate\Http\JsonResponse; -use Illuminate\Support\Optional; use Spatie\LaravelData\Attributes\Validation\Min; use Spatie\LaravelData\Attributes\Validation\Numeric; +use Spatie\LaravelData\Optional; /** * @extends LookupDataCommand diff --git a/app/Dto/CharactersSearchCommand.php b/app/Dto/CharactersSearchCommand.php index 0bb7a89..0954240 100644 --- a/app/Dto/CharactersSearchCommand.php +++ b/app/Dto/CharactersSearchCommand.php @@ -6,11 +6,11 @@ use App\Casts\EnumCast; use App\Contracts\DataRequest; use App\Enums\CharacterOrderByEnum; use App\Http\Resources\V4\CharacterCollection; -use Illuminate\Support\Optional; use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\MapInputName; use Spatie\LaravelData\Attributes\MapOutputName; use Spatie\LaravelData\Attributes\WithCast; +use Spatie\LaravelData\Optional; /** * @implements DataRequest diff --git a/app/Dto/ClubSearchCommand.php b/app/Dto/ClubSearchCommand.php index 6d855a1..e64d5ea 100644 --- a/app/Dto/ClubSearchCommand.php +++ b/app/Dto/ClubSearchCommand.php @@ -8,11 +8,11 @@ use App\Enums\ClubCategoryEnum; use App\Enums\ClubOrderByEnum; use App\Enums\ClubTypeEnum; use App\Http\Resources\V4\ClubCollection; -use Illuminate\Support\Optional; use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\MapInputName; use Spatie\LaravelData\Attributes\MapOutputName; use Spatie\LaravelData\Attributes\WithCast; +use Spatie\LaravelData\Optional; /** * @implements DataRequest diff --git a/app/Dto/Concerns/HasLimitParameter.php b/app/Dto/Concerns/HasLimitParameter.php new file mode 100644 index 0000000..de4dfce --- /dev/null +++ b/app/Dto/Concerns/HasLimitParameter.php @@ -0,0 +1,16 @@ + + */ +abstract class LookupByUsernameCommand extends Data implements DataRequest +{ + use MapsRouteParameters, HasRequestFingerprint; + + #[StringType, Max(255), Min(3)] + public string $username; +} diff --git a/app/Dto/MagazineSearchCommand.php b/app/Dto/MagazineSearchCommand.php index 98c6a4a..c3025c4 100644 --- a/app/Dto/MagazineSearchCommand.php +++ b/app/Dto/MagazineSearchCommand.php @@ -6,11 +6,11 @@ use App\Casts\EnumCast; use App\Contracts\DataRequest; use App\Enums\MagazineOrderByEnum; use App\Http\Resources\V4\MagazineCollection; -use Illuminate\Support\Optional; use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\MapInputName; use Spatie\LaravelData\Attributes\MapOutputName; use Spatie\LaravelData\Attributes\WithCast; +use Spatie\LaravelData\Optional; /** * @implements DataRequest diff --git a/app/Dto/MangaForumLookupCommand.php b/app/Dto/MangaForumLookupCommand.php index 4615286..94c3112 100644 --- a/app/Dto/MangaForumLookupCommand.php +++ b/app/Dto/MangaForumLookupCommand.php @@ -6,9 +6,9 @@ namespace App\Dto; use App\Casts\EnumCast; use App\Enums\MangaForumFilterEnum; use Illuminate\Http\JsonResponse; -use Illuminate\Support\Optional; use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\WithCast; +use Spatie\LaravelData\Optional; /** * @extends LookupDataCommand diff --git a/app/Dto/PeopleSearchCommand.php b/app/Dto/PeopleSearchCommand.php index a9699f4..78aa3e4 100644 --- a/app/Dto/PeopleSearchCommand.php +++ b/app/Dto/PeopleSearchCommand.php @@ -6,11 +6,11 @@ use App\Casts\EnumCast; use App\Contracts\DataRequest; use App\Enums\PeopleOrderByEnum; use App\Http\Resources\V4\PersonCollection; -use Illuminate\Support\Optional; use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\MapInputName; use Spatie\LaravelData\Attributes\MapOutputName; use Spatie\LaravelData\Attributes\WithCast; +use Spatie\LaravelData\Optional; /** * @implements DataRequest diff --git a/app/Dto/ProducersSearchCommand.php b/app/Dto/ProducersSearchCommand.php index 4ab48f9..8803911 100644 --- a/app/Dto/ProducersSearchCommand.php +++ b/app/Dto/ProducersSearchCommand.php @@ -6,11 +6,11 @@ use App\Casts\EnumCast; use App\Contracts\DataRequest; use App\Enums\ProducerOrderByEnum; use App\Http\Resources\V4\ProducerCollection; -use Illuminate\Support\Optional; use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\MapInputName; use Spatie\LaravelData\Attributes\MapOutputName; use Spatie\LaravelData\Attributes\WithCast; +use Spatie\LaravelData\Optional; /** * @implements DataRequest diff --git a/app/Dto/QueryAnimeSchedulesCommand.php b/app/Dto/QueryAnimeSchedulesCommand.php index d42aaf4..cb2d9cc 100644 --- a/app/Dto/QueryAnimeSchedulesCommand.php +++ b/app/Dto/QueryAnimeSchedulesCommand.php @@ -6,18 +6,14 @@ namespace App\Dto; use App\Casts\EnumCast; use App\Concerns\HasRequestFingerprint; use App\Contracts\DataRequest; -use App\Dto\Concerns\MapsDefaultLimitParameter; +use App\Dto\Concerns\HasLimitParameter; +use App\Dto\Concerns\HasPageParameter; use App\Enums\AnimeScheduleFilterEnum; -use App\Rules\Attributes\MaxLimitWithFallback; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Support\Env; use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\Validation\BooleanType; -use Spatie\LaravelData\Attributes\Validation\IntegerType; -use Spatie\LaravelData\Attributes\Validation\Min; use Spatie\LaravelData\Attributes\Validation\Nullable; -use Spatie\LaravelData\Attributes\Validation\Numeric; use Spatie\LaravelData\Attributes\WithCast; use Spatie\LaravelData\Data; use Spatie\LaravelData\Optional; @@ -27,13 +23,7 @@ use Spatie\LaravelData\Optional; */ final class QueryAnimeSchedulesCommand extends Data implements DataRequest { - use MapsDefaultLimitParameter, HasRequestFingerprint; - - #[Numeric, Min(1)] - public int|Optional $page = 1; - - #[IntegerType, Min(1), MaxLimitWithFallback] - public int|Optional $limit; + use HasLimitParameter, HasRequestFingerprint, HasPageParameter; #[BooleanType] public bool|Optional $kids = false; diff --git a/app/Dto/QueryAnimeSeasonCommand.php b/app/Dto/QueryAnimeSeasonCommand.php index a27d017..303a84d 100644 --- a/app/Dto/QueryAnimeSeasonCommand.php +++ b/app/Dto/QueryAnimeSeasonCommand.php @@ -6,12 +6,10 @@ namespace App\Dto; use App\Casts\EnumCast; use App\Concerns\HasRequestFingerprint; use App\Contracts\DataRequest; -use App\Dto\Concerns\MapsDefaultLimitParameter; +use App\Dto\Concerns\HasLimitParameter; +use App\Dto\Concerns\HasPageParameter; use App\Enums\AnimeTypeEnum; -use App\Rules\Attributes\MaxLimitWithFallback; use Spatie\Enum\Laravel\Rules\EnumRule; -use Spatie\LaravelData\Attributes\Validation\Min; -use Spatie\LaravelData\Attributes\Validation\Numeric; use Spatie\LaravelData\Attributes\WithCast; use Spatie\LaravelData\Data; use Spatie\LaravelData\Optional; @@ -19,18 +17,11 @@ use Spatie\LaravelData\Optional; abstract class QueryAnimeSeasonCommand extends Data implements DataRequest { - use MapsDefaultLimitParameter, HasRequestFingerprint; + use HasLimitParameter, HasRequestFingerprint, HasPageParameter; #[WithCast(EnumCast::class, AnimeTypeEnum::class)] public AnimeTypeEnum|Optional $filter; - #[Numeric, Min(1)] - public int|Optional $page = 1; - - #[Numeric, Min(1), MaxLimitWithFallback] - public int|Optional $limit; - - public static function rules(...$args): array { return [ diff --git a/app/Dto/QueryRandomAnimeCommand.php b/app/Dto/QueryRandomAnimeCommand.php index d544e36..e77c347 100644 --- a/app/Dto/QueryRandomAnimeCommand.php +++ b/app/Dto/QueryRandomAnimeCommand.php @@ -4,9 +4,9 @@ namespace App\Dto; use App\Contracts\DataRequest; use App\Http\Resources\V4\AnimeResource; -use Illuminate\Support\Optional; use Spatie\LaravelData\Attributes\Validation\BooleanType; use Spatie\LaravelData\Data; +use Spatie\LaravelData\Optional; /** * @implements DataRequest diff --git a/app/Dto/QueryRandomMangaCommand.php b/app/Dto/QueryRandomMangaCommand.php index ccf8b52..74b7ab6 100644 --- a/app/Dto/QueryRandomMangaCommand.php +++ b/app/Dto/QueryRandomMangaCommand.php @@ -4,9 +4,9 @@ namespace App\Dto; use App\Contracts\DataRequest; use App\Http\Resources\V4\MangaResource; -use Illuminate\Support\Optional; use Spatie\LaravelData\Attributes\Validation\BooleanType; use Spatie\LaravelData\Data; +use Spatie\LaravelData\Optional; /** * @implements DataRequest diff --git a/app/Dto/QueryRecentlyOnlineUsersCommand.php b/app/Dto/QueryRecentlyOnlineUsersCommand.php new file mode 100644 index 0000000..03999df --- /dev/null +++ b/app/Dto/QueryRecentlyOnlineUsersCommand.php @@ -0,0 +1,15 @@ + + */ +final class QueryRecentlyOnlineUsersCommand extends Data implements DataRequest +{ +} diff --git a/app/Dto/QueryReviewsCommand.php b/app/Dto/QueryReviewsCommand.php index 2684453..7f9d346 100644 --- a/app/Dto/QueryReviewsCommand.php +++ b/app/Dto/QueryReviewsCommand.php @@ -6,6 +6,7 @@ namespace App\Dto; use App\Casts\EnumCast; use App\Concerns\HasRequestFingerprint; use App\Contracts\DataRequest; +use App\Dto\Concerns\HasPageParameter; use App\Enums\MediaReviewsSortEnum; use App\Http\Resources\V4\ResultsResource; use Spatie\Enum\Laravel\Rules\EnumRule; @@ -21,10 +22,7 @@ use Spatie\LaravelData\Optional; */ abstract class QueryReviewsCommand extends Data implements DataRequest { - use HasRequestFingerprint; - - #[Numeric, Min(1)] - public int|Optional $page = 1; + use HasRequestFingerprint, HasPageParameter; #[WithCast(EnumCast::class, MediaReviewsSortEnum::class)] public MediaReviewsSortEnum|Optional $sort; diff --git a/app/Dto/QueryTopItemsCommand.php b/app/Dto/QueryTopItemsCommand.php index 5c56060..2e5bb84 100644 --- a/app/Dto/QueryTopItemsCommand.php +++ b/app/Dto/QueryTopItemsCommand.php @@ -2,20 +2,11 @@ namespace App\Dto; -use App\Dto\Concerns\MapsDefaultLimitParameter; -use App\Rules\Attributes\MaxLimitWithFallback; -use Illuminate\Support\Optional; -use Spatie\LaravelData\Attributes\Validation\Min; -use Spatie\LaravelData\Attributes\Validation\Numeric; +use App\Dto\Concerns\HasLimitParameter; +use App\Dto\Concerns\HasPageParameter; use Spatie\LaravelData\Data; abstract class QueryTopItemsCommand extends Data { - use MapsDefaultLimitParameter; - - #[Numeric, Min(1)] - public int|Optional $page = 1; - - #[Numeric, Min(1), MaxLimitWithFallback] - public int|Optional $limit; + use HasLimitParameter, HasPageParameter; } diff --git a/app/Dto/QueryTopMangaItemsCommand.php b/app/Dto/QueryTopMangaItemsCommand.php index 7dc6e4a..b2b21d3 100644 --- a/app/Dto/QueryTopMangaItemsCommand.php +++ b/app/Dto/QueryTopMangaItemsCommand.php @@ -7,10 +7,9 @@ use App\Contracts\DataRequest; use App\Enums\MangaTypeEnum; use App\Enums\TopMangaFilterEnum; use App\Http\Resources\V4\MangaCollection; -use Illuminate\Support\Optional; use Spatie\Enum\Laravel\Rules\EnumRule; -use Spatie\LaravelData\Attributes\Validation\Rule; use Spatie\LaravelData\Attributes\WithCast; +use Spatie\LaravelData\Optional; /** * @implements DataRequest diff --git a/app/Dto/SearchCommand.php b/app/Dto/SearchCommand.php index a344006..74c1d0f 100644 --- a/app/Dto/SearchCommand.php +++ b/app/Dto/SearchCommand.php @@ -3,17 +3,12 @@ namespace App\Dto; use App\Casts\EnumCast; -use App\Dto\Concerns\MapsDefaultLimitParameter; +use App\Dto\Concerns\HasLimitParameter; +use App\Dto\Concerns\HasPageParameter; use App\Enums\SortDirection; -use App\Rules\Attributes\MaxLimitWithFallback; use Spatie\Enum\Laravel\Rules\EnumRule; -use Spatie\LaravelData\Attributes\MapInputName; -use Spatie\LaravelData\Attributes\MapOutputName; use Spatie\LaravelData\Attributes\Validation\Alpha; -use Spatie\LaravelData\Attributes\Validation\IntegerType; use Spatie\LaravelData\Attributes\Validation\Max; -use Spatie\LaravelData\Attributes\Validation\Min; -use Spatie\LaravelData\Attributes\Validation\Numeric; use Spatie\LaravelData\Attributes\Validation\Size; use Spatie\LaravelData\Attributes\Validation\StringType; use Spatie\LaravelData\Attributes\WithCast; @@ -22,7 +17,7 @@ use Spatie\LaravelData\Optional; class SearchCommand extends Data { - use MapsDefaultLimitParameter; + use HasLimitParameter, HasPageParameter; /** * The search keywords @@ -31,12 +26,6 @@ class SearchCommand extends Data #[Max(255), StringType] public string|Optional $q; - #[Numeric, Min(1)] - public int|Optional $page = 1; - - #[IntegerType, Min(1), MaxLimitWithFallback] - public int|Optional $limit; - #[WithCast(EnumCast::class, SortDirection::class)] public SortDirection|Optional $sort; diff --git a/app/Dto/UserAboutLookupCommand.php b/app/Dto/UserAboutLookupCommand.php new file mode 100644 index 0000000..35980b3 --- /dev/null +++ b/app/Dto/UserAboutLookupCommand.php @@ -0,0 +1,13 @@ + + */ +final class UserAboutLookupCommand extends LookupByUsernameCommand +{ +} diff --git a/app/Dto/UserClubsLookupCommand.php b/app/Dto/UserClubsLookupCommand.php new file mode 100644 index 0000000..64252e8 --- /dev/null +++ b/app/Dto/UserClubsLookupCommand.php @@ -0,0 +1,13 @@ + + */ +final class UserClubsLookupCommand extends LookupByUsernameCommand +{ +} diff --git a/app/Dto/UserExternalLookupCommand.php b/app/Dto/UserExternalLookupCommand.php new file mode 100644 index 0000000..85b46c6 --- /dev/null +++ b/app/Dto/UserExternalLookupCommand.php @@ -0,0 +1,13 @@ + + */ +final class UserExternalLookupCommand extends LookupByUsernameCommand +{ +} diff --git a/app/Dto/UserFavoritesLookupCommand.php b/app/Dto/UserFavoritesLookupCommand.php new file mode 100644 index 0000000..ef05ba1 --- /dev/null +++ b/app/Dto/UserFavoritesLookupCommand.php @@ -0,0 +1,13 @@ + + */ +final class UserFavoritesLookupCommand extends LookupByUsernameCommand +{ +} diff --git a/app/Dto/UserFriendsLookupCommand.php b/app/Dto/UserFriendsLookupCommand.php new file mode 100644 index 0000000..44e6a06 --- /dev/null +++ b/app/Dto/UserFriendsLookupCommand.php @@ -0,0 +1,15 @@ + + */ +final class UserFriendsLookupCommand extends LookupByUsernameCommand +{ + use HasPageParameter; +} diff --git a/app/Dto/UserFullLookupCommand.php b/app/Dto/UserFullLookupCommand.php new file mode 100644 index 0000000..0c3acca --- /dev/null +++ b/app/Dto/UserFullLookupCommand.php @@ -0,0 +1,13 @@ + + */ +final class UserFullLookupCommand extends LookupByUsernameCommand +{ +} diff --git a/app/Dto/UserHistoryLookupCommand.php b/app/Dto/UserHistoryLookupCommand.php new file mode 100644 index 0000000..a234091 --- /dev/null +++ b/app/Dto/UserHistoryLookupCommand.php @@ -0,0 +1,27 @@ + + */ +final class UserHistoryLookupCommand extends LookupByUsernameCommand +{ + #[WithCast(EnumCast::class, UserHistoryTypeEnum::class)] + public ?UserHistoryTypeEnum $type; + + public static function rules(...$args): array + { + return [ + "type" => [new EnumRule(UserHistoryTypeEnum::class), new Nullable()] + ]; + } +} diff --git a/app/Dto/UserProfileLookupCommand.php b/app/Dto/UserProfileLookupCommand.php new file mode 100644 index 0000000..44e18fa --- /dev/null +++ b/app/Dto/UserProfileLookupCommand.php @@ -0,0 +1,13 @@ + + */ +final class UserProfileLookupCommand extends LookupByUsernameCommand +{ +} diff --git a/app/Dto/UserRecommendationsLookupCommand.php b/app/Dto/UserRecommendationsLookupCommand.php new file mode 100644 index 0000000..0f3dde2 --- /dev/null +++ b/app/Dto/UserRecommendationsLookupCommand.php @@ -0,0 +1,15 @@ + + */ +final class UserRecommendationsLookupCommand extends LookupByUsernameCommand +{ + use HasPageParameter; +} diff --git a/app/Dto/UserReviewsLookupCommand.php b/app/Dto/UserReviewsLookupCommand.php new file mode 100644 index 0000000..7156602 --- /dev/null +++ b/app/Dto/UserReviewsLookupCommand.php @@ -0,0 +1,15 @@ + + */ +final class UserReviewsLookupCommand extends LookupByUsernameCommand +{ + use HasPageParameter; +} diff --git a/app/Dto/UserStatisticsLookupCommand.php b/app/Dto/UserStatisticsLookupCommand.php new file mode 100644 index 0000000..4d3d628 --- /dev/null +++ b/app/Dto/UserStatisticsLookupCommand.php @@ -0,0 +1,13 @@ + + */ +final class UserStatisticsLookupCommand extends LookupByUsernameCommand +{ +} diff --git a/app/Dto/UserUpdatesLookupCommand.php b/app/Dto/UserUpdatesLookupCommand.php new file mode 100644 index 0000000..b3058dc --- /dev/null +++ b/app/Dto/UserUpdatesLookupCommand.php @@ -0,0 +1,13 @@ + + */ +final class UserUpdatesLookupCommand extends LookupByUsernameCommand +{ +} diff --git a/app/Dto/UsersSearchCommand.php b/app/Dto/UsersSearchCommand.php index 4a5a781..e400dfc 100644 --- a/app/Dto/UsersSearchCommand.php +++ b/app/Dto/UsersSearchCommand.php @@ -7,10 +7,10 @@ use App\Concerns\HasRequestFingerprint; use App\Contracts\DataRequest; use App\Enums\GenderEnum; use App\Http\Resources\V4\UserCollection; -use Illuminate\Support\Optional; use Spatie\Enum\Laravel\Rules\EnumRule; use Spatie\LaravelData\Attributes\Validation\StringType; use Spatie\LaravelData\Attributes\WithCast; +use Spatie\LaravelData\Optional; /** * @implements DataRequest diff --git a/app/Enums/UserHistoryTypeEnum.php b/app/Enums/UserHistoryTypeEnum.php new file mode 100644 index 0000000..0d5ef84 --- /dev/null +++ b/app/Enums/UserHistoryTypeEnum.php @@ -0,0 +1,14 @@ + + */ +final class QueryRecentlyOnlineUsersHandler extends RequestHandlerWithScraperCache +{ + public function requestClass(): string + { + return QueryRecentlyOnlineUsersCommand::class; + } + + protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData + { + return $this->scraperService->findList( + $requestFingerPrint, + fn(MalClient $jikan, ?int $page = null) => ["results" => $jikan->getRecentOnlineUsers(new RecentlyOnlineUsersRequest())] + ); + } +} diff --git a/app/Features/UserAboutLookupHandler.php b/app/Features/UserAboutLookupHandler.php new file mode 100644 index 0000000..1cde103 --- /dev/null +++ b/app/Features/UserAboutLookupHandler.php @@ -0,0 +1,24 @@ + + */ +final class UserAboutLookupHandler extends UserLookupHandler +{ + public function requestClass(): string + { + return UserAboutLookupCommand::class; + } + + protected function resource(Collection $results): JsonResource + { + return new ProfileAboutResource($results->first()); + } +} diff --git a/app/Features/UserClubsLookupHandler.php b/app/Features/UserClubsLookupHandler.php new file mode 100644 index 0000000..0cbd96f --- /dev/null +++ b/app/Features/UserClubsLookupHandler.php @@ -0,0 +1,30 @@ + + */ +final class UserClubsLookupHandler extends RequestHandlerWithScraperCache +{ + public function requestClass(): string + { + return UserClubsLookupCommand::class; + } + + protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData + { + $username = $requestParams->get("username"); + return $this->scraperService->findList( + $requestFingerPrint, + fn(MalClient $jikan, ?int $page = null) => ["results" => $jikan->getUserClubs(new UserClubsRequest($username))] + ); + } +} diff --git a/app/Features/UserExternalLookupHandler.php b/app/Features/UserExternalLookupHandler.php new file mode 100644 index 0000000..b4f0f77 --- /dev/null +++ b/app/Features/UserExternalLookupHandler.php @@ -0,0 +1,24 @@ + + */ +final class UserExternalLookupHandler extends UserLookupHandler +{ + public function requestClass(): string + { + return UserExternalLookupCommand::class; + } + + protected function resource(Collection $results): JsonResource + { + return new ExternalLinksResource($results->first()); + } +} diff --git a/app/Features/UserFavoritesLookupHandler.php b/app/Features/UserFavoritesLookupHandler.php new file mode 100644 index 0000000..db61853 --- /dev/null +++ b/app/Features/UserFavoritesLookupHandler.php @@ -0,0 +1,24 @@ + + */ +final class UserFavoritesLookupHandler extends UserLookupHandler +{ + public function requestClass(): string + { + return UserFavoritesLookupCommand::class; + } + + protected function resource(Collection $results): JsonResource + { + return new ProfileFavoritesResource($results->first()); + } +} diff --git a/app/Features/UserFriendsLookupHandler.php b/app/Features/UserFriendsLookupHandler.php new file mode 100644 index 0000000..f6b880c --- /dev/null +++ b/app/Features/UserFriendsLookupHandler.php @@ -0,0 +1,31 @@ + + */ +final class UserFriendsLookupHandler extends RequestHandlerWithScraperCache +{ + public function requestClass(): string + { + return UserFriendsLookupCommand::class; + } + + protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData + { + $username = $requestParams->get("username"); + return $this->scraperService->findList( + $requestFingerPrint, + fn(MalClient $jikan, ?int $page = null) => $jikan->getUserFriends(new UserFriendsRequest($username, $page)), + $requestParams->get("page", 1) + ); + } +} diff --git a/app/Features/UserFullLookupHandler.php b/app/Features/UserFullLookupHandler.php new file mode 100644 index 0000000..65463ef --- /dev/null +++ b/app/Features/UserFullLookupHandler.php @@ -0,0 +1,24 @@ + + */ +final class UserFullLookupHandler extends UserLookupHandler +{ + public function requestClass(): string + { + return UserFullLookupCommand::class; + } + + protected function resource(Collection $results): JsonResource + { + return new ProfileFullResource($results->first()); + } +} diff --git a/app/Features/UserHistoryLookupHandler.php b/app/Features/UserHistoryLookupHandler.php new file mode 100644 index 0000000..bf9ecd4 --- /dev/null +++ b/app/Features/UserHistoryLookupHandler.php @@ -0,0 +1,39 @@ + + */ +final class UserHistoryLookupHandler extends RequestHandlerWithScraperCache +{ + public function requestClass(): string + { + return UserHistoryLookupCommand::class; + } + + protected function resource(Collection $results): JsonResource + { + return new ProfileHistoryResource($results->first()); + } + + protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData + { + $type = $requestParams->get("type"); + $username = $requestParams->get("username"); + return $this->scraperService->findList( + $requestFingerPrint, + fn(MalClient $jikan, ?int $page = null) => ["history" => $jikan->getUserHistory(new UserHistoryRequest( + $username, $type + ))] + ); + } +} diff --git a/app/Features/UserLookupHandler.php b/app/Features/UserLookupHandler.php new file mode 100644 index 0000000..10aee4f --- /dev/null +++ b/app/Features/UserLookupHandler.php @@ -0,0 +1,26 @@ + + */ +abstract class UserLookupHandler extends RequestHandlerWithScraperCache +{ + protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData + { + $username = $requestParams->get("username"); + return $this->scraperService->findByKey( + "username", + $username, + $requestFingerPrint, + ); + } +} diff --git a/app/Features/UserProfileLookupHandler.php b/app/Features/UserProfileLookupHandler.php new file mode 100644 index 0000000..fee379e --- /dev/null +++ b/app/Features/UserProfileLookupHandler.php @@ -0,0 +1,24 @@ + + */ +final class UserProfileLookupHandler extends UserLookupHandler +{ + public function requestClass(): string + { + return UserProfileLookupCommand::class; + } + + protected function resource(Collection $results): JsonResource + { + return new ProfileResource($results->first()); + } +} diff --git a/app/Features/UserRecommendationsLookupHandler.php b/app/Features/UserRecommendationsLookupHandler.php new file mode 100644 index 0000000..a1bf92b --- /dev/null +++ b/app/Features/UserRecommendationsLookupHandler.php @@ -0,0 +1,31 @@ + + */ +final class UserRecommendationsLookupHandler extends RequestHandlerWithScraperCache +{ + public function requestClass(): string + { + return UserRecommendationsLookupCommand::class; + } + + protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData + { + $username = $requestParams->get("username"); + return $this->scraperService->findList( + $requestFingerPrint, + fn(MalClient $jikan, ?int $page = null) => $jikan->getUserRecommendations(new UserRecommendationsRequest($username, $page)), + $requestParams->get("page", 1) + ); + } +} diff --git a/app/Features/UserReviewsLookupHandler.php b/app/Features/UserReviewsLookupHandler.php new file mode 100644 index 0000000..2dd892f --- /dev/null +++ b/app/Features/UserReviewsLookupHandler.php @@ -0,0 +1,36 @@ + + */ +final class UserReviewsLookupHandler extends RequestHandlerWithScraperCache +{ + public function requestClass(): string + { + return UserReviewsLookupCommand::class; + } + + protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData + { + $username = $requestParams->get("username"); + return $this->scraperService->findList( + $requestFingerPrint, + fn(MalClient $jikan, ?int $page = null) => $jikan->getUserReviews( + new UserReviewsRequest( + $username, + $page, + ) + ), + $requestParams->get("page", 1) + ); + } +} diff --git a/app/Features/UserStatisticsLookupHandler.php b/app/Features/UserStatisticsLookupHandler.php new file mode 100644 index 0000000..c00becf --- /dev/null +++ b/app/Features/UserStatisticsLookupHandler.php @@ -0,0 +1,24 @@ + + */ +final class UserStatisticsLookupHandler extends UserLookupHandler +{ + public function requestClass(): string + { + return UserStatisticsLookupCommand::class; + } + + protected function resource(Collection $results): JsonResource + { + return new ProfileStatisticsResource($results->first()); + } +} diff --git a/app/Features/UserUpdatesLookupHandler.php b/app/Features/UserUpdatesLookupHandler.php new file mode 100644 index 0000000..f271dc4 --- /dev/null +++ b/app/Features/UserUpdatesLookupHandler.php @@ -0,0 +1,24 @@ + + */ +final class UserUpdatesLookupHandler extends UserLookupHandler +{ + public function requestClass(): string + { + return UserUpdatesLookupCommand::class; + } + + protected function resource(Collection $results): JsonResource + { + return new ProfileLastUpdatesResource($results->first()); + } +} diff --git a/app/Http/Controllers/V4DB/Traits/JikanApiQueryBuilder.php b/app/Http/Controllers/V4DB/Traits/JikanApiQueryBuilder.php deleted file mode 100644 index 8543436..0000000 --- a/app/Http/Controllers/V4DB/Traits/JikanApiQueryBuilder.php +++ /dev/null @@ -1,37 +0,0 @@ -searchQueryBuilderProvider->getQueryBuilder($name); - return $queryBuilder->query($request); - } - - protected function getPaginator(string $name, Request $request, \Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder $results): \Illuminate\Contracts\Pagination\LengthAwarePaginator - { - $queryBuilder = $this->searchQueryBuilderProvider->getQueryBuilder($name); - return $queryBuilder->paginateBuilder($request, $results); - } - - /** - * @template T - * @param class-string $resourceCollectionClass - * @param string $resourceTypeName - * @param \Illuminate\Http\Request $request - * @return T - */ - protected function preparePaginatedResponse(string $resourceCollectionClass, string $resourceTypeName, Request $request) - { - $results = $this->getQueryBuilder($resourceTypeName, $request); - $paginator = $this->getPaginator($resourceTypeName, $request, $results); - return new $resourceCollectionClass($paginator); - } -} diff --git a/app/Http/Controllers/V4DB/UserController.php b/app/Http/Controllers/V4DB/UserController.php index 5a90f75..5fa541a 100644 --- a/app/Http/Controllers/V4DB/UserController.php +++ b/app/Http/Controllers/V4DB/UserController.php @@ -2,29 +2,20 @@ namespace App\Http\Controllers\V4DB; -use App\Http\HttpResponse; -use App\Http\QueryBuilder\UserListQueryBuilder; -use App\Http\Resources\V4\ExternalLinksResource; -use App\Http\Resources\V4\ProfileHistoryResource; -use App\Http\Resources\V4\ResultsResource; -use App\Http\Resources\V4\UserProfileAnimeListCollection; -use App\Http\Resources\V4\UserProfileAnimeListResource; -use App\Http\Resources\V4\UserProfileMangaListCollection; -use App\Http\Resources\V4\UserProfileMangaListResource; -use App\Profile; +use App\Dto\QueryRecentlyOnlineUsersCommand; +use App\Dto\UserAboutLookupCommand; +use App\Dto\UserClubsLookupCommand; +use App\Dto\UserExternalLookupCommand; +use App\Dto\UserFavoritesLookupCommand; +use App\Dto\UserFriendsLookupCommand; +use App\Dto\UserFullLookupCommand; +use App\Dto\UserHistoryLookupCommand; +use App\Dto\UserProfileLookupCommand; +use App\Dto\UserRecommendationsLookupCommand; +use App\Dto\UserReviewsLookupCommand; +use App\Dto\UserStatisticsLookupCommand; +use App\Dto\UserUpdatesLookupCommand; use Illuminate\Http\Request; -use Illuminate\Support\Facades\DB; -use Jikan\Helper\Constants; -use Jikan\Request\User\RecentlyOnlineUsersRequest; -use Jikan\Request\User\UserAnimeListRequest; -use Jikan\Request\User\UserClubsRequest; -use Jikan\Request\User\UserFriendsRequest; -use Jikan\Request\User\UserHistoryRequest; -use Jikan\Request\User\UserMangaListRequest; -use Jikan\Request\User\UserRecommendationsRequest; -use Jikan\Request\User\UserReviewsRequest; -use MongoDB\BSON\UTCDateTime; -use Symfony\Component\HttpFoundation\Exception\BadRequestException; /** * Class Controller @@ -62,61 +53,9 @@ class UserController extends Controller * ), * ), */ - public function full(Request $request, string $username) + public function full(UserFullLookupCommand $command) { - $username = strtolower($username); - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $response = Profile::scrape($username); - - if ($results->isEmpty()) { - $meta = [ - 'createdAt' => new UTCDateTime(), - 'modifiedAt' => new UTCDateTime(), - 'request_hash' => $this->fingerprint, - 'internal_username' => $username - ]; - } - $meta['modifiedAt'] = new UTCDateTime(); - - $response = $meta + $response; - - if ($results->isEmpty()) { - Profile::query() - ->insert($response); - } - - if ($this->isExpired($request, $results)) { - Profile::query() - ->where('internal_username', $username) - ->update($response); - } - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - } - - if ($results->isEmpty()) { - return HttpResponse::notFound($request); - } - - $response = (new \App\Http\Resources\V4\ProfileFullResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -148,61 +87,9 @@ class UserController extends Controller * ), * ), */ - public function profile(Request $request, string $username) + public function profile(UserProfileLookupCommand $command) { - $username = strtolower($username); - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $response = Profile::scrape($username); - - if ($results->isEmpty()) { - $meta = [ - 'createdAt' => new UTCDateTime(), - 'modifiedAt' => new UTCDateTime(), - 'request_hash' => $this->fingerprint, - 'internal_username' => $username - ]; - } - $meta['modifiedAt'] = new UTCDateTime(); - - $response = $meta + $response; - - if ($results->isEmpty()) { - Profile::query() - ->insert($response); - } - - if ($this->isExpired($request, $results)) { - Profile::query() - ->where('internal_username', $username) - ->update($response); - } - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - } - - if ($results->isEmpty()) { - return HttpResponse::notFound($request); - } - - $response = (new \App\Http\Resources\V4\ProfileResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -231,62 +118,9 @@ class UserController extends Controller * ), * ), */ - public function statistics(Request $request, string $username) + public function statistics(UserStatisticsLookupCommand $command) { - - $username = strtolower($username); - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $response = Profile::scrape($username); - - if ($results->isEmpty()) { - $meta = [ - 'createdAt' => new UTCDateTime(), - 'modifiedAt' => new UTCDateTime(), - 'request_hash' => $this->fingerprint, - 'internal_username' => $username - ]; - } - $meta['modifiedAt'] = new UTCDateTime(); - - $response = $meta + $response; - - if ($results->isEmpty()) { - Profile::query() - ->insert($response); - } - - if ($this->isExpired($request, $results)) { - Profile::query() - ->where('internal_username', $username) - ->update($response); - } - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - } - - if ($results->isEmpty()) { - return HttpResponse::notFound($request); - } - - $response = (new \App\Http\Resources\V4\ProfileStatisticsResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } @@ -319,62 +153,9 @@ class UserController extends Controller * ), * ), */ - public function favorites(Request $request, string $username) + public function favorites(UserFavoritesLookupCommand $command) { - - $username = strtolower($username); - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $response = Profile::scrape($username); - - if ($results->isEmpty()) { - $meta = [ - 'createdAt' => new UTCDateTime(), - 'modifiedAt' => new UTCDateTime(), - 'request_hash' => $this->fingerprint, - 'internal_username' => $username - ]; - } - $meta['modifiedAt'] = new UTCDateTime(); - - $response = $meta + $response; - - if ($results->isEmpty()) { - Profile::query() - ->insert($response); - } - - if ($this->isExpired($request, $results)) { - Profile::query() - ->where('internal_username', $username) - ->update($response); - } - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - } - - if ($results->isEmpty()) { - return HttpResponse::notFound($request); - } - - $response = (new \App\Http\Resources\V4\ProfileFavoritesResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -403,62 +184,9 @@ class UserController extends Controller * ), * ), */ - public function userupdates(Request $request, string $username) + public function userupdates(UserUpdatesLookupCommand $command) { - - $username = strtolower($username); - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $response = Profile::scrape($username); - - if ($results->isEmpty()) { - $meta = [ - 'createdAt' => new UTCDateTime(), - 'modifiedAt' => new UTCDateTime(), - 'request_hash' => $this->fingerprint, - 'internal_username' => $username - ]; - } - $meta['modifiedAt'] = new UTCDateTime(); - - $response = $meta + $response; - - if ($results->isEmpty()) { - Profile::query() - ->insert($response); - } - - if ($this->isExpired($request, $results)) { - Profile::query() - ->where('internal_username', $username) - ->update($response); - } - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - } - - if ($results->isEmpty()) { - return HttpResponse::notFound($request); - } - - $response = (new \App\Http\Resources\V4\ProfileLastUpdatesResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -487,62 +215,9 @@ class UserController extends Controller * ), * ), */ - public function about(Request $request, string $username) + public function about(UserAboutLookupCommand $command) { - - $username = strtolower($username); - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $response = Profile::scrape($username); - - if ($results->isEmpty()) { - $meta = [ - 'createdAt' => new UTCDateTime(), - 'modifiedAt' => new UTCDateTime(), - 'request_hash' => $this->fingerprint, - 'internal_username' => $username - ]; - } - $meta['modifiedAt'] = new UTCDateTime(); - - $response = $meta + $response; - - if ($results->isEmpty()) { - Profile::query() - ->insert($response); - } - - if ($this->isExpired($request, $results)) { - Profile::query() - ->where('internal_username', $username) - ->update($response); - } - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - } - - if ($results->isEmpty()) { - return HttpResponse::notFound($request); - } - - $response = (new \App\Http\Resources\V4\ProfileAboutResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -578,45 +253,9 @@ class UserController extends Controller * ), * ), */ - public function history(Request $request, string $username, ?string $type = null) + public function history(UserHistoryLookupCommand $command) { - $filter = $request->get('filter') ?? null; - - if (!is_null($type)) { - $type = strtolower($type); - } - - if (!is_null($filter) && is_null($type)) { - $type = strtolower($filter); - } - - if (!is_null($type) && !\in_array($type, ['anime', 'manga'])) { - return HttpResponse::badRequest($request); - } - - $results = DB::table($this->getRouteTable($request)) - ->where('request_hash', $this->fingerprint) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $data = ['history'=>$this->jikan->getUserHistory(new UserHistoryRequest($username, $type))]; - $response = \json_decode($this->serializer->serialize($data, 'json'), true); - - $results = $this->updateCache($request, $results, $response); - } - - $response = (new ProfileHistoryResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -690,32 +329,9 @@ class UserController extends Controller * } * ), */ - public function friends(Request $request, string $username) + public function friends(UserFriendsLookupCommand $command) { - $results = DB::table($this->getRouteTable($request)) - ->where('request_hash', $this->fingerprint) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $page = $request->get('page') ?? 1; - $data = $this->jikan->getUserFriends(new UserFriendsRequest($username, $page)); - $response = \json_decode($this->serializer->serialize($data, 'json'), true); - - $results = $this->updateCache($request, $results, $response); - } - - $response = (new ResultsResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -748,51 +364,8 @@ class UserController extends Controller */ public function animelist(Request $request, string $username, ?string $status = null) { - if (!is_null($status)) { - $status = strtolower($status); - - if (!\in_array($status, ['all', 'watching', 'completed', 'onhold', 'dropped', 'plantowatch'])) { - return HttpResponse::badRequest($request); - } - } - $status = $this->listStatusToId($status); - - - $results = DB::table($this->getRouteTable($request)) - ->where('request_hash', $this->fingerprint) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $page = $request->get('page') ?? 1; - $data = $this->jikan->getUserAnimeList( - UserListQueryBuilder::create( - $request, - new UserAnimeListRequest($username, $page, $status) - ) - ); - $response = ['anime' => \json_decode($this->serializer->serialize($data, 'json'), true)]; - - $results = $this->updateCache($request, $results, $response); - } - - $listResults = $results->first()['anime']; - - foreach ($listResults as &$result) { - $result = (new UserProfileAnimeListResource($result)); - } - - $response = (new UserProfileAnimeListCollection( - $listResults - ))->response($request); - - return $this->prepareResponse( - $response, - $results, - $request - ); + // noop, intentionally left blank + // todo: remove as this is obsolete } /** @@ -825,52 +398,8 @@ class UserController extends Controller */ public function mangalist(Request $request, string $username, ?string $status = null) { - if (!is_null($status)) { - $status = strtolower($status); - - if (!\in_array($status, ['all', 'reading', 'completed', 'onhold', 'dropped', 'plantoread', 'ptr'])) { - return response()->json([ - 'error' => 'Bad Request' - ])->setStatusCode(400); - } - } - $status = $this->listStatusToId($status); - - $results = DB::table($this->getRouteTable($request)) - ->where('request_hash', $this->fingerprint) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $page = $request->get('page') ?? 1; - $data = $this->jikan->getUserMangaList( - UserListQueryBuilder::create( - $request, - new UserMangaListRequest($username, $page, $status) - ) - ); - $response = ['manga' => \json_decode($this->serializer->serialize($data, 'json'), true)]; - - $results = $this->updateCache($request, $results, $response); - } - - $listResults = $results->first()['manga']; - - foreach ($listResults as &$result) { - $result = (new UserProfileMangaListResource($result)); - } - - $response = (new UserProfileMangaListCollection( - $listResults - ))->response($request); - - return $this->prepareResponse( - $response, - $results, - $request - ); + // noop, intentionally left blank + // todo: remove as this is obsolete } /** @@ -955,39 +484,9 @@ class UserController extends Controller * ), * ), */ - public function reviews(Request $request, string $username) + public function reviews(UserReviewsLookupCommand $command) { - $results = DB::table($this->getRouteTable($request)) - ->where('request_hash', $this->fingerprint) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $page = $request->get('page') ?? 1; - - $data = $this->jikan - ->getUserReviews( - new UserReviewsRequest( - $username, - $page, - ) - ); - - $response = \json_decode($this->serializer->serialize($data, 'json'), true); - $results = $this->updateCache($request, $results, $response); - } - - $response = (new ResultsResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -1017,32 +516,9 @@ class UserController extends Controller * ), * */ - public function recommendations(Request $request, string $username) + public function recommendations(UserRecommendationsLookupCommand $command) { - $results = DB::table($this->getRouteTable($request)) - ->where('request_hash', $this->fingerprint) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $page = $request->get('page') ?? 1; - $data = $this->jikan->getUserRecommendations(new UserRecommendationsRequest($username, $page)); - $response = \json_decode($this->serializer->serialize($data, 'json'), true); - - $results = $this->updateCache($request, $results, $response); - } - - $response = (new ResultsResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -1106,31 +582,9 @@ class UserController extends Controller * } * ), */ - public function clubs(Request $request, string $username) + public function clubs(UserClubsLookupCommand $command) { - $results = DB::table($this->getRouteTable($request)) - ->where('request_hash', $this->fingerprint) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $data = ['results' => $this->jikan->getUserClubs(new UserClubsRequest($username))]; - $response = \json_decode($this->serializer->serialize($data, 'json'), true); - - $results = $this->updateCache($request, $results, $response); - } - - $response = (new ResultsResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } /** @@ -1160,125 +614,13 @@ class UserController extends Controller * ), * ), */ - public function external(Request $request, string $username) + public function external(UserExternalLookupCommand $command) { - $username = strtolower($username); - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $response = Profile::scrape($username); - - if ($results->isEmpty()) { - $meta = [ - 'createdAt' => new UTCDateTime(), - 'modifiedAt' => new UTCDateTime(), - 'request_hash' => $this->fingerprint, - 'internal_username' => $username - ]; - } - $meta['modifiedAt'] = new UTCDateTime(); - - $response = $meta + $response; - - if ($results->isEmpty()) { - Profile::query() - ->insert($response); - } - - if ($this->isExpired($request, $results)) { - Profile::query() - ->where('internal_username', $username) - ->update($response); - } - - $results = Profile::query() - ->where('internal_username', $username) - ->get(); - } - - if ($results->isEmpty()) { - return HttpResponse::notFound($request); - } - - $response = (new ExternalLinksResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); + return $this->mediator->send($command); } - /** - * @param Request $request - * @return mixed - * @throws \Jikan\Exception\BadResponseException - * @throws \Jikan\Exception\ParserException - */ - public function recentlyOnline(Request $request) + public function recentlyOnline(QueryRecentlyOnlineUsersCommand $command) { - $results = DB::table($this->getRouteTable($request)) - ->where('request_hash', $this->fingerprint) - ->get(); - - if ( - $results->isEmpty() - || $this->isExpired($request, $results) - ) { - $data = ['results'=>$this->jikan->getRecentOnlineUsers(new RecentlyOnlineUsersRequest())]; - $response = \json_decode($this->serializer->serialize($data, 'json'), true); - - $results = $this->updateCache($request, $results, $response); - } - - $response = (new ResultsResource( - $results->first() - ))->response(); - - return $this->prepareResponse( - $response, - $results, - $request - ); - } - - /** - * @param string|null $status - * @return int - */ - private function listStatusToId(?string $status) : int - { - if (is_null($status)) { - return 7; - } - - switch ($status) { - case 'all': - return 7; - case 'watching': - case 'reading': - return 1; - case 'completed': - return 2; - case 'onhold': - return 3; - case 'dropped': - return 4; - case 'plantowatch': - case 'ptw': - case 'plantoread': - case 'ptr': - return 6; - default: - return 7; - } + return $this->mediator->send($command); } } diff --git a/app/Http/Middleware/EndpointCacheTtlMiddleware.php b/app/Http/Middleware/EndpointCacheTtlMiddleware.php new file mode 100644 index 0000000..07fc5b3 --- /dev/null +++ b/app/Http/Middleware/EndpointCacheTtlMiddleware.php @@ -0,0 +1,33 @@ +jikanConfig->cacheTtlForEndpoint($routeName); + $this->cacheOptions->setTtl($ttl); + + $response = $next($request); + + $this->cacheOptions->setTtl(null); + return $response; + } +} diff --git a/app/Macros/ResponseJikanCacheFlags.php b/app/Macros/ResponseJikanCacheFlags.php index 34a75b1..1851fe7 100644 --- a/app/Macros/ResponseJikanCacheFlags.php +++ b/app/Macros/ResponseJikanCacheFlags.php @@ -2,8 +2,8 @@ namespace App\Macros; -use App\Concerns\ScraperCacheTtl; use App\Support\CachedData; +use App\Support\CacheOptions; use Illuminate\Http\Response; use Illuminate\Support\Carbon; @@ -12,8 +12,6 @@ use Illuminate\Support\Carbon; */ final class ResponseJikanCacheFlags { - use ScraperCacheTtl; - public function __invoke(): \Closure { return function (string $cacheKey, CachedData $scraperResults) { @@ -22,7 +20,7 @@ final class ResponseJikanCacheFlags */ return $this ->header("X-Request-Fingerprint", $cacheKey) - ->setTtl(ResponseJikanCacheFlags::cacheTtl()) + ->setTtl(app(CacheOptions::class)->ttl()) ->setExpires(Carbon::createFromTimestamp($scraperResults->expiry())) ->setLastModified(Carbon::createFromTimestamp($scraperResults->lastModified())); }; diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 878ec0b..9725fb2 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -15,22 +15,11 @@ use App\Contracts\Repository; use App\Contracts\RequestHandler; use App\Contracts\UnitOfWork; use App\Contracts\UserRepository; -use App\GenreAnime; -use App\GenreManga; -use App\Http\QueryBuilder\AnimeSearchQueryBuilder; -use App\Http\QueryBuilder\CharacterSearchQueryBuilder; -use App\Http\QueryBuilder\ClubSearchQueryBuilder; -use App\Http\QueryBuilder\PeopleSearchQueryBuilder; -use App\Http\QueryBuilder\SimpleSearchQueryBuilder; -use App\Http\QueryBuilder\MangaSearchQueryBuilder; -use App\Http\QueryBuilder\TopAnimeQueryBuilder; -use App\Http\QueryBuilder\TopMangaQueryBuilder; +use App\Http\Middleware\EndpointCacheTtlMiddleware; use App\Macros\CollectionOffsetGetFirst; use App\Macros\ResponseJikanCacheFlags; use App\Macros\To2dArrayWithDottedKeys; -use App\Magazine; use App\Mixins\ScoutBuilderMixin; -use App\Producers; use App\Repositories\AnimeGenresRepository; use App\Repositories\DefaultAnimeRepository; use App\Repositories\DefaultCharacterRepository; @@ -53,7 +42,9 @@ use App\Services\ScoutSearchService; use App\Services\SearchEngineSearchService; use App\Services\SearchService; use App\Services\TypeSenseScoutSearchService; +use App\Support\CacheOptions; use App\Support\DefaultMediator; +use App\Support\JikanConfig; use App\Support\JikanUnitOfWork; use Illuminate\Contracts\Container\BindingResolutionException; use Illuminate\Http\JsonResponse; @@ -87,6 +78,9 @@ class AppServiceProvider extends ServiceProvider */ public function register(): void { + $this->app->singleton(JikanConfig::class, fn() => new JikanConfig(config("jikan"))); + // cache options class is used to share the request scope level cache settings + $this->app->singleton(CacheOptions::class); $this->app->singleton(CachedScraperService::class, DefaultCachedScraperService::class); if ($this->getSearchIndexesEnabledConfig($this->app)) { $this->app->bind(QueryBuilderPaginatorService::class, ScoutBuilderPaginatorService::class); @@ -268,7 +262,20 @@ class AppServiceProvider extends ServiceProvider Features\QueryMangaRecommendationsHandler::class => $unitOfWorkInstance->documents("recommendations"), Features\QueryAnimeReviewsHandler::class => $unitOfWorkInstance->documents("reviews"), Features\QueryMangaReviewsHandler::class => $unitOfWorkInstance->documents("reviews"), - Features\QueryAnimeSeasonListHandler::class => $unitOfWorkInstance->documents("season_archive") + Features\QueryAnimeSeasonListHandler::class => $unitOfWorkInstance->documents("season_archive"), + Features\UserFullLookupHandler::class => $unitOfWorkInstance->users(), + Features\UserProfileLookupHandler::class => $unitOfWorkInstance->users(), + Features\UserStatisticsLookupHandler::class => $unitOfWorkInstance->users(), + Features\UserFavoritesLookupHandler::class => $unitOfWorkInstance->users(), + Features\UserUpdatesLookupHandler::class => $unitOfWorkInstance->users(), + Features\UserAboutLookupHandler::class => $unitOfWorkInstance->users(), + Features\UserHistoryLookupHandler::class => $unitOfWorkInstance->documents("users_history"), + Features\UserFriendsLookupHandler::class => $unitOfWorkInstance->documents("users_friends"), + Features\UserReviewsLookupHandler::class => $unitOfWorkInstance->documents("users_reviews"), + Features\UserRecommendationsLookupHandler::class => $unitOfWorkInstance->documents("users_recommendations"), + Features\UserClubsLookupHandler::class => $unitOfWorkInstance->documents("users_clubs"), + Features\UserExternalLookupHandler::class => $unitOfWorkInstance->users(), + Features\QueryRecentlyOnlineUsersHandler::class => $unitOfWorkInstance->documents("users_recently_online") ]; foreach ($requestHandlersWithScraperService as $handlerClass => $repositoryInstance) { @@ -347,15 +354,11 @@ class AppServiceProvider extends ServiceProvider public static function servicesToWarm(): array { + // todo: test again with roadrunner -- specific issue: typesense driver not loaded in time $services = [ ScoutSearchService::class, - AnimeSearchQueryBuilder::class, - MangaSearchQueryBuilder::class, - ClubSearchQueryBuilder::class, - CharacterSearchQueryBuilder::class, - PeopleSearchQueryBuilder::class, - TopAnimeQueryBuilder::class, - TopMangaQueryBuilder::class + UnitOfWork::class, + CachedScraperService::class ]; if (Env::get("SCOUT_DRIVER") === "typesense") { @@ -366,6 +369,12 @@ class AppServiceProvider extends ServiceProvider $services[] = \Elastic\Elasticsearch\Client::class; } + if (Env::get("SCOUT_DRIVER") !== "none" && Env::get("SCOUT_DRIVER")) { + $services[] = ScoutBuilderPaginatorService::class; + } else { + $services[] = EloquentBuilderPaginatorService::class; + } + return $services; } } diff --git a/app/Repositories/DefaultCharacterRepository.php b/app/Repositories/DefaultCharacterRepository.php index 8dfb13a..2737d61 100644 --- a/app/Repositories/DefaultCharacterRepository.php +++ b/app/Repositories/DefaultCharacterRepository.php @@ -5,13 +5,13 @@ namespace App\Repositories; use App\Character; use App\Contracts\CharacterRepository; use App\Contracts\Repository; -use Illuminate\Database\Eloquent\Builder as EloquentBuilder; +use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder; use Laravel\Scout\Builder as ScoutBuilder; /** * @implements Repository */ -class DefaultCharacterRepository extends DatabaseRepository implements CharacterRepository +final class DefaultCharacterRepository extends DatabaseRepository implements CharacterRepository { public function __construct() { diff --git a/app/Repositories/DefaultClubRepository.php b/app/Repositories/DefaultClubRepository.php index 1d9c561..05e27ff 100644 --- a/app/Repositories/DefaultClubRepository.php +++ b/app/Repositories/DefaultClubRepository.php @@ -9,7 +9,7 @@ use App\Contracts\Repository; /** * @implements Repository */ -class DefaultClubRepository extends DatabaseRepository implements ClubRepository +final class DefaultClubRepository extends DatabaseRepository implements ClubRepository { public function __construct() { diff --git a/app/Repositories/DefaultMagazineRepository.php b/app/Repositories/DefaultMagazineRepository.php index 6c891c2..7d58188 100644 --- a/app/Repositories/DefaultMagazineRepository.php +++ b/app/Repositories/DefaultMagazineRepository.php @@ -9,7 +9,7 @@ use App\Magazine; /** * @implements Repository */ -class DefaultMagazineRepository extends DatabaseRepository implements MagazineRepository +final class DefaultMagazineRepository extends DatabaseRepository implements MagazineRepository { public function __construct() { diff --git a/app/Repositories/DefaultMangaRepository.php b/app/Repositories/DefaultMangaRepository.php index acd5d84..f588146 100644 --- a/app/Repositories/DefaultMangaRepository.php +++ b/app/Repositories/DefaultMangaRepository.php @@ -9,7 +9,7 @@ use App\Manga; use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder; use Laravel\Scout\Builder as ScoutBuilder; -class DefaultMangaRepository extends DatabaseRepository implements MangaRepository +final class DefaultMangaRepository extends DatabaseRepository implements MangaRepository { public function __construct() { diff --git a/app/Repositories/DefaultPeopleRepository.php b/app/Repositories/DefaultPeopleRepository.php index aae0670..71f0994 100644 --- a/app/Repositories/DefaultPeopleRepository.php +++ b/app/Repositories/DefaultPeopleRepository.php @@ -5,7 +5,7 @@ namespace App\Repositories; use App\Contracts\PeopleRepository; use App\Contracts\Repository; use App\Person; -use Illuminate\Database\Eloquent\Builder as EloquentBuilder; +use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder; use Laravel\Scout\Builder as ScoutBuilder; /** diff --git a/app/Repositories/DefaultProducerRepository.php b/app/Repositories/DefaultProducerRepository.php index b545f9e..17aa80e 100644 --- a/app/Repositories/DefaultProducerRepository.php +++ b/app/Repositories/DefaultProducerRepository.php @@ -9,7 +9,7 @@ use App\Producers; /** * @implements Repository */ -class DefaultProducerRepository extends DatabaseRepository implements ProducerRepository +final class DefaultProducerRepository extends DatabaseRepository implements ProducerRepository { public function __construct() { diff --git a/app/Repositories/DefaultUserRepository.php b/app/Repositories/DefaultUserRepository.php index 68e176c..bd22618 100644 --- a/app/Repositories/DefaultUserRepository.php +++ b/app/Repositories/DefaultUserRepository.php @@ -9,7 +9,7 @@ use App\Profile; /** * @implements Repository */ -class DefaultUserRepository extends DatabaseRepository implements UserRepository +final class DefaultUserRepository extends DatabaseRepository implements UserRepository { public function __construct() { diff --git a/app/Services/DefaultCachedScraperService.php b/app/Services/DefaultCachedScraperService.php index cc9c3f5..543f4e1 100644 --- a/app/Services/DefaultCachedScraperService.php +++ b/app/Services/DefaultCachedScraperService.php @@ -2,7 +2,6 @@ namespace App\Services; -use App\Concerns\ScraperCacheTtl; use App\Contracts\CachedScraperService; use App\Contracts\Repository; use App\Http\HttpHelper; @@ -19,8 +18,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; */ final class DefaultCachedScraperService implements CachedScraperService { - use ScraperCacheTtl; - public function __construct( private readonly Repository $repository, private readonly MalClient $jikan, @@ -133,7 +130,7 @@ final class DefaultCachedScraperService implements CachedScraperService $this->repository->queryByMalId($id)->update($response->toArray()); } - return new CachedData(collect($this->repository->getAllByMalId($id))); + return CachedData::from(collect($this->repository->getAllByMalId($id))); } private function updateCacheByKey(string $cacheKey, CachedData $results, array $scraperResponse): CachedData @@ -149,7 +146,7 @@ final class DefaultCachedScraperService implements CachedScraperService $this->getQueryableByCacheKey($cacheKey)->update($response->toArray()); } - return new CachedData($this->getByCacheKey($cacheKey)); + return CachedData::from($this->getByCacheKey($cacheKey)); } private function prepareScraperResponse(string $cacheKey, bool $resultsEmpty, array $scraperResponse): CachedData @@ -166,7 +163,7 @@ final class DefaultCachedScraperService implements CachedScraperService $meta['modifiedAt'] = new UTCDateTime(); // join meta data with response - return new CachedData(collect($meta + $scraperResponse)); + return CachedData::from(collect($meta + $scraperResponse)); } private function getByCacheKey(string $cacheKey): Collection @@ -179,7 +176,7 @@ final class DefaultCachedScraperService implements CachedScraperService return $this->repository->where("request_hash", $cacheKey); } - private function serializeScraperResult(array $data): array + private function serializeScraperResult(mixed $data): array { return $this->serializer->toArray($data); } diff --git a/app/Support/CacheOptions.php b/app/Support/CacheOptions.php new file mode 100644 index 0000000..71be4fb --- /dev/null +++ b/app/Support/CacheOptions.php @@ -0,0 +1,22 @@ +ttl ?? $this->jikanConfig->defaultCacheExpire(); + } + + public function setTtl(?int $ttl): void + { + $this->ttl = $ttl; + } +} diff --git a/app/Support/CachedData.php b/app/Support/CachedData.php index f526e53..e148cf6 100644 --- a/app/Support/CachedData.php +++ b/app/Support/CachedData.php @@ -5,20 +5,23 @@ namespace App\Support; use App\Concerns\ScraperCacheTtl; use App\JikanApiModel; use Illuminate\Support\Collection; +use Illuminate\Support\Env; final class CachedData { - use ScraperCacheTtl; + private int $cacheTimeToLive; - public function __construct( - private readonly Collection $scraperResult + private function __construct( + private readonly Collection $scraperResult, + int $cacheTtl ) { + $this->cacheTimeToLive = $cacheTtl; } public static function from(Collection $scraperResult): self { - return new self($scraperResult); + return new self($scraperResult, app(CacheOptions::class)->ttl()); } public function collect(): Collection @@ -62,10 +65,15 @@ final class CachedData public function expiry(): int { $modifiedAt = $this->lastModified(); - $ttl = $this->cacheTtl(); + $ttl = $this->cacheTimeToLive; return $modifiedAt !== null ? $ttl + $modifiedAt : $ttl; } + public function cacheTtl(): int + { + return $this->cacheTimeToLive; + } + public function lastModified(): ?int { if ($this->scraperResult->isEmpty()) { diff --git a/app/Support/JikanConfig.php b/app/Support/JikanConfig.php new file mode 100644 index 0000000..d8d8ced --- /dev/null +++ b/app/Support/JikanConfig.php @@ -0,0 +1,35 @@ + $perEndpointCacheTtl + */ + private array $perEndpointCacheTtl; + + private int $defaultCacheExpire; + + public function __construct(array $config) + { + $config = collect($config); + $this->perEndpointCacheTtl = $config->get("per_endpoint_cache_ttl", []); + $this->defaultCacheExpire = $config->get("default_cache_expire", 0); + } + + public function cacheTtlForEndpoint(string $endpoint): ?int + { + return collect($this->perEndpointCacheTtl)->get($endpoint); + } + + public function defaultCacheExpire(): int + { + return $this->defaultCacheExpire; + } +} diff --git a/app/Support/RepositoryQueryBase.php b/app/Support/RepositoryQueryBase.php index def93a0..0463586 100644 --- a/app/Support/RepositoryQueryBase.php +++ b/app/Support/RepositoryQueryBase.php @@ -6,8 +6,8 @@ use Illuminate\Contracts\Database\Query\Builder; class RepositoryQueryBase { - private ?Builder $queryableBuilder; - private ?ScoutBuilder $searchableBuilder; + private ?Builder $queryableBuilder = null; + private ?ScoutBuilder $searchableBuilder = null; public function __construct( private readonly \Closure $getQueryable, diff --git a/bootstrap/app.php b/bootstrap/app.php index fdc5429..460c89e 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -41,7 +41,6 @@ $app->instance('path.config', app()->basePath() . DIRECTORY_SEPARATOR . 'config' $app->instance('path.storage', app()->basePath() . DIRECTORY_SEPARATOR . 'storage'); $app->withEloquent(); - $app->configure('swagger-lume'); $app->configure('scout'); @@ -88,6 +87,7 @@ $app->middleware($globalMiddleware); $app->routeMiddleware([ 'microcaching' => \App\Http\Middleware\MicroCaching::class, 'source-health-monitor' => SourceHeartbeatMonitor::class, + 'cache-ttl' => \App\Http\Middleware\EndpointCacheTtlMiddleware::class ]); /* @@ -109,6 +109,7 @@ $app->configure('controller-to-table-mapping'); $app->configure('controller'); $app->configure('roadrunner'); $app->configure('data'); +$app->configure('jikan'); $app->register(\pushrbx\LumenRoadRunner\ServiceProvider::class); $app->register(\SwaggerLume\ServiceProvider::class); @@ -169,6 +170,7 @@ if (env("SCOUT_DRIVER") === "Matchish\ScoutElasticSearch\Engines\ElasticSearchEn $commonMiddleware = [ 'source-health-monitor', 'microcaching', + 'cache-ttl' ]; diff --git a/config/jikan.php b/config/jikan.php new file mode 100644 index 0000000..870df5c --- /dev/null +++ b/config/jikan.php @@ -0,0 +1,143 @@ + env('CACHE_DEFAULT_EXPIRE', 86400), + 'per_endpoint_cache_ttl' => [ + /** + * Anime + */ + 'AnimeController@main' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@characters_staff' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@characters' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@staff' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@episodes' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@episode' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@news' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@forum' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@videos' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@videosEpisodes' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@pictures' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@stats' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@moreInfo' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@recommendations' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@userupdates' => env('CACHE_DEFAULT_EXPIRE'), + 'AnimeController@reviews' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Manga + */ + 'MangaController@main' => env('CACHE_DEFAULT_EXPIRE'), + 'MangaController@characters' => env('CACHE_DEFAULT_EXPIRE'), + 'MangaController@news' => env('CACHE_DEFAULT_EXPIRE'), + 'MangaController@forum' => env('CACHE_DEFAULT_EXPIRE'), + 'MangaController@pictures' => env('CACHE_DEFAULT_EXPIRE'), + 'MangaController@stats' => env('CACHE_DEFAULT_EXPIRE'), + 'MangaController@moreInfo' => env('CACHE_DEFAULT_EXPIRE'), + 'MangaController@recommendations' => env('CACHE_DEFAULT_EXPIRE'), + 'MangaController@userupdates' => env('CACHE_DEFAULT_EXPIRE'), + 'MangaController@reviews' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Characters + */ + 'CharacterController@main' => env('CACHE_DEFAULT_EXPIRE'), + 'CharacterController@anime' => env('CACHE_DEFAULT_EXPIRE'), + 'CharacterController@manga' => env('CACHE_DEFAULT_EXPIRE'), + 'CharacterController@voices' => env('CACHE_DEFAULT_EXPIRE'), + 'CharacterController@pictures' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Person + */ + 'PersonController@main' => env('CACHE_DEFAULT_EXPIRE'), + 'PersonController@anime' => env('CACHE_DEFAULT_EXPIRE'), + 'PersonController@manga' => env('CACHE_DEFAULT_EXPIRE'), + 'PersonController@seiyuu' => env('CACHE_DEFAULT_EXPIRE'), + 'PersonController@pictures' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Season + */ + 'SeasonController@archive' => env('CACHE_DEFAULT_EXPIRE'), + 'SeasonController@later' => env('CACHE_DEFAULT_EXPIRE'), + 'SeasonController@main' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Schedule + */ + 'ScheduleController@main' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Producers + */ + 'ProducerController@main' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Magazines + */ + 'MagazineController@main' => env('CACHE_MAGAZINE_EXPIRE'), + 'MagazineController@resource' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Users + */ + 'UserController@recentlyOnline' => env('CACHE_DEFAULT_EXPIRE'), + 'UserController@profile' => env('CACHE_USER_EXPIRE'), + 'UserController@statistics' => env('CACHE_USER_EXPIRE'), + 'UserController@favorites' => env('CACHE_USER_EXPIRE'), + 'UserController@about' => env('CACHE_USER_EXPIRE'), + 'UserController@history' => env('CACHE_USER_EXPIRE'), + 'UserController@friends' => env('CACHE_USER_EXPIRE'), + 'UserController@recommendations' => env('CACHE_USER_EXPIRE'), + 'UserController@reviews' => env('CACHE_USER_EXPIRE'), + 'UserController@clubs' => env('CACHE_USER_EXPIRE'), + + /** + * User Lists + */ + 'UserController@animelist' => env('CACHE_USERLIST_EXPIRE'), + 'UserController@mangalist' => env('CACHE_USERLIST_EXPIRE'), + + /** + * Genre + */ + 'GenreController@mainAnime' => env('CACHE_GENRE_EXPIRE'), + 'GenreController@mainManga' => env('CACHE_GENRE_EXPIRE'), + 'GenreController@anime' => env('CACHE_DEFAULT_EXPIRE'), + 'GenreController@manga' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Top + */ + 'TopController@anime' => env('CACHE_DEFAULT_EXPIRE'), + 'TopController@manga' => env('CACHE_DEFAULT_EXPIRE'), + 'TopController@characters' => env('CACHE_DEFAULT_EXPIRE'), + 'TopController@people' => env('CACHE_DEFAULT_EXPIRE'), + 'TopController@reviews' => env('CACHE_DEFAULT_EXPIRE'), + + /** + * Search + */ + 'SearchController@anime' => env('CACHE_SEARCH_EXPIRE'), + 'SearchController@manga' => env('CACHE_SEARCH_EXPIRE'), + 'SearchController@character' => env('CACHE_SEARCH_EXPIRE'), + 'SearchController@people' => env('CACHE_SEARCH_EXPIRE'), + 'SearchController@users' => env('CACHE_SEARCH_EXPIRE'), + 'SearchController@userById' => env('CACHE_SEARCH_EXPIRE'), + 'SearchController@producers' => env('CACHE_SEARCH_EXPIRE'), + + 'ClubController@main' => env('CACHE_DEFAULT_EXPIRE'), + 'ClubController@members' => env('CACHE_DEFAULT_EXPIRE'), + + 'ReviewsController@anime' => env('CACHE_DEFAULT_EXPIRE'), + 'ReviewsController@manga' => env('CACHE_DEFAULT_EXPIRE'), + + 'RecommendationsController@anime' => env('CACHE_DEFAULT_EXPIRE'), + 'RecommendationsController@manga' => env('CACHE_DEFAULT_EXPIRE'), + + 'WatchController@recentEpisodes' => env('CACHE_DEFAULT_EXPIRE'), + 'WatchController@popularEpisodes' => env('CACHE_DEFAULT_EXPIRE'), + 'WatchController@recentPromos' => env('CACHE_DEFAULT_EXPIRE'), + 'WatchController@popularPromos' => env('CACHE_DEFAULT_EXPIRE'), + ] +]; diff --git a/database/factories/JikanMediaModelFactory.php b/database/factories/JikanMediaModelFactory.php index 8d97166..44a8575 100644 --- a/database/factories/JikanMediaModelFactory.php +++ b/database/factories/JikanMediaModelFactory.php @@ -15,7 +15,7 @@ abstract class JikanMediaModelFactory extends JikanModelFactory implements Media { use JikanDataGenerator; - protected ?MediaModelFactoryDescriptor $descriptor; + protected ?MediaModelFactoryDescriptor $descriptor = null; public function __construct( MediaModelFactoryDescriptor $descriptor,