mirror of
https://github.com/jikan-me/jikan-rest.git
synced 2025-02-20 11:23:35 +08:00
wip - mediator refactor
- anime schedules - validation and corrections - refactorings around "augmentResponse" - macro usage instead
This commit is contained in:
parent
c564de979d
commit
49ebc8f581
@ -4,6 +4,7 @@ namespace App\Concerns;
|
||||
|
||||
use App\Http\HttpHelper;
|
||||
use Illuminate\Http\Request;
|
||||
use Spatie\LaravelData\Resolvers\DataFromSomethingResolver;
|
||||
|
||||
/**
|
||||
* Helper trait for data transfer objects
|
||||
@ -16,7 +17,8 @@ trait HasRequestFingerprint
|
||||
|
||||
public static function fromRequest(Request $request): ?static
|
||||
{
|
||||
$result = new self();
|
||||
$result = app(DataFromSomethingResolver::class)
|
||||
->withoutMagicalCreation()->execute(self::class, $request);
|
||||
$result->fingerprint = HttpHelper::resolveRequestFingerprint($request);
|
||||
return $result;
|
||||
}
|
||||
|
@ -2,10 +2,12 @@
|
||||
|
||||
namespace App\Concerns;
|
||||
|
||||
use Illuminate\Support\Env;
|
||||
|
||||
trait ScraperCacheTtl
|
||||
{
|
||||
protected function cacheTtl(): int
|
||||
protected static function cacheTtl(): int
|
||||
{
|
||||
return (int) env('CACHE_DEFAULT_EXPIRE');
|
||||
return (int) Env::get('CACHE_DEFAULT_EXPIRE');
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
namespace App\Contracts;
|
||||
|
||||
use App\Anime;
|
||||
use \Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use App\Enums\AnimeScheduleFilterEnum;
|
||||
use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder;
|
||||
use \Laravel\Scout\Builder as ScoutBuilder;
|
||||
|
||||
/**
|
||||
@ -22,4 +23,10 @@ interface AnimeRepository extends Repository
|
||||
public function orderByFavoriteCount(): EloquentBuilder|ScoutBuilder;
|
||||
|
||||
public function orderByRank(): EloquentBuilder|ScoutBuilder;
|
||||
|
||||
public function getCurrentlyAiring(
|
||||
?AnimeScheduleFilterEnum $filter = null,
|
||||
bool $kids = false,
|
||||
bool $sfw = false
|
||||
): EloquentBuilder;
|
||||
}
|
||||
|
@ -33,6 +33,4 @@ interface CachedScraperService
|
||||
public function findByKey(string $key, mixed $val, string $cacheKey): CachedData;
|
||||
|
||||
public function get(string $cacheKey): CachedData;
|
||||
|
||||
public function augmentResponse(JsonResponse|Response $response, string $cacheKey, CachedData $scraperResults): JsonResponse|Response;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
namespace App\Contracts;
|
||||
|
||||
use App\Manga;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder;
|
||||
use Laravel\Scout\Builder as ScoutBuilder;
|
||||
|
||||
/**
|
||||
@ -20,4 +20,6 @@ interface MangaRepository extends Repository
|
||||
public function orderByFavoriteCount(): EloquentBuilder|ScoutBuilder;
|
||||
|
||||
public function orderByRank(): EloquentBuilder|ScoutBuilder;
|
||||
|
||||
public function exceptItemsWithAdultRating(): EloquentBuilder|ScoutBuilder;
|
||||
}
|
||||
|
@ -33,4 +33,6 @@ interface Repository extends RepositoryQuery
|
||||
public function scrape(int|string $id): array;
|
||||
|
||||
public function insert(array $attributes): bool;
|
||||
|
||||
public function random(int $numberOfRandomItems = 1): Collection;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Dto;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
@ -11,6 +12,6 @@ use Spatie\LaravelData\Optional;
|
||||
*/
|
||||
final class AnimeEpisodesLookupCommand extends LookupDataCommand
|
||||
{
|
||||
#[Numeric]
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Dto;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
@ -11,6 +12,6 @@ use Spatie\LaravelData\Optional;
|
||||
*/
|
||||
final class AnimeNewsLookupCommand extends LookupDataCommand
|
||||
{
|
||||
#[Numeric]
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use App\Enums\MediaReviewsSortEnum;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Spatie\Enum\Laravel\Rules\EnumRule;
|
||||
use Spatie\LaravelData\Attributes\Validation\BooleanType;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Attributes\WithCast;
|
||||
use Spatie\LaravelData\Optional;
|
||||
@ -16,7 +17,7 @@ use Spatie\LaravelData\Optional;
|
||||
*/
|
||||
final class AnimeReviewsLookupCommand extends LookupDataCommand
|
||||
{
|
||||
#[Numeric]
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
|
||||
#[WithCast(EnumCast::class, MediaReviewsSortEnum::class)]
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Dto;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
@ -11,6 +12,6 @@ use Spatie\LaravelData\Optional;
|
||||
*/
|
||||
final class AnimeUserUpdatesLookupCommand extends LookupDataCommand
|
||||
{
|
||||
#[Numeric]
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace App\Dto;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Optional;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
|
||||
/**
|
||||
@ -11,6 +12,6 @@ use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
*/
|
||||
final class AnimeVideosEpisodesLookupCommand extends LookupDataCommand
|
||||
{
|
||||
#[Numeric]
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Dto;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
@ -11,6 +12,6 @@ use Spatie\LaravelData\Optional;
|
||||
*/
|
||||
final class ClubMembersLookupCommand extends LookupDataCommand
|
||||
{
|
||||
#[Numeric]
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
@ -12,6 +13,6 @@ use Spatie\LaravelData\Optional;
|
||||
*/
|
||||
final class MangaNewsLookupCommand extends LookupDataCommand
|
||||
{
|
||||
#[Numeric]
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use App\Enums\MediaReviewsSortEnum;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Spatie\Enum\Laravel\Rules\EnumRule;
|
||||
use Spatie\LaravelData\Attributes\Validation\BooleanType;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Attributes\WithCast;
|
||||
use Spatie\LaravelData\Optional;
|
||||
@ -17,7 +18,7 @@ use Spatie\LaravelData\Optional;
|
||||
*/
|
||||
final class MangaReviewsLookupCommand extends LookupDataCommand
|
||||
{
|
||||
#[Numeric]
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
|
||||
#[WithCast(EnumCast::class, MediaReviewsSortEnum::class)]
|
||||
|
@ -4,6 +4,7 @@ namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
@ -12,6 +13,6 @@ use Spatie\LaravelData\Optional;
|
||||
*/
|
||||
final class MangaUserUpdatesLookupCommand extends LookupDataCommand
|
||||
{
|
||||
#[Numeric]
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
}
|
||||
|
13
app/Dto/PersonAnimeLookupCommand.php
Normal file
13
app/Dto/PersonAnimeLookupCommand.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @extends LookupDataCommand<JsonResponse>
|
||||
*/
|
||||
final class PersonAnimeLookupCommand extends LookupDataCommand
|
||||
{
|
||||
}
|
13
app/Dto/PersonFullLookupCommand.php
Normal file
13
app/Dto/PersonFullLookupCommand.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @extends LookupDataCommand<JsonResponse>
|
||||
*/
|
||||
final class PersonFullLookupCommand extends LookupDataCommand
|
||||
{
|
||||
}
|
13
app/Dto/PersonLookupCommand.php
Normal file
13
app/Dto/PersonLookupCommand.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @extends LookupDataCommand<JsonResponse>
|
||||
*/
|
||||
final class PersonLookupCommand extends LookupDataCommand
|
||||
{
|
||||
}
|
13
app/Dto/PersonMangaLookupCommand.php
Normal file
13
app/Dto/PersonMangaLookupCommand.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @extends LookupDataCommand<JsonResponse>
|
||||
*/
|
||||
final class PersonMangaLookupCommand extends LookupDataCommand
|
||||
{
|
||||
}
|
13
app/Dto/PersonPicturesLookupCommand.php
Normal file
13
app/Dto/PersonPicturesLookupCommand.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @extends LookupDataCommand<JsonResponse>
|
||||
*/
|
||||
final class PersonPicturesLookupCommand extends LookupDataCommand
|
||||
{
|
||||
}
|
13
app/Dto/PersonVoicesLookupCommand.php
Normal file
13
app/Dto/PersonVoicesLookupCommand.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @extends LookupDataCommand<JsonResponse>
|
||||
*/
|
||||
final class PersonVoicesLookupCommand extends LookupDataCommand
|
||||
{
|
||||
}
|
13
app/Dto/ProducerExternalLookupCommand.php
Normal file
13
app/Dto/ProducerExternalLookupCommand.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @extends LookupDataCommand<JsonResponse>
|
||||
*/
|
||||
final class ProducerExternalLookupCommand extends LookupDataCommand
|
||||
{
|
||||
}
|
13
app/Dto/ProducerFullLookupCommand.php
Normal file
13
app/Dto/ProducerFullLookupCommand.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @extends LookupDataCommand<JsonResponse>
|
||||
*/
|
||||
final class ProducerFullLookupCommand extends LookupDataCommand
|
||||
{
|
||||
}
|
13
app/Dto/ProducerLookupCommand.php
Normal file
13
app/Dto/ProducerLookupCommand.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* @extends LookupDataCommand<JsonResponse>
|
||||
*/
|
||||
final class ProducerLookupCommand extends LookupDataCommand
|
||||
{
|
||||
}
|
17
app/Dto/QueryAnimeRecommendationsCommand.php
Normal file
17
app/Dto/QueryAnimeRecommendationsCommand.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use App\Concerns\HasRequestFingerprint;
|
||||
use App\Contracts\DataRequest;
|
||||
use App\Http\Resources\V4\ResultsResource;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
/**
|
||||
* @implements DataRequest<ResultsResource>
|
||||
*/
|
||||
final class QueryAnimeRecommendationsCommand extends Data implements DataRequest
|
||||
{
|
||||
use HasRequestFingerprint;
|
||||
}
|
7
app/Dto/QueryAnimeReviewsCommand.php
Normal file
7
app/Dto/QueryAnimeReviewsCommand.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
final class QueryAnimeReviewsCommand extends QueryReviewsCommand
|
||||
{
|
||||
}
|
64
app/Dto/QueryAnimeSchedulesCommand.php
Normal file
64
app/Dto/QueryAnimeSchedulesCommand.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use App\Casts\EnumCast;
|
||||
use App\Concerns\HasRequestFingerprint;
|
||||
use App\Contracts\DataRequest;
|
||||
use App\Enums\AnimeScheduleFilterEnum;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @implements DataRequest<JsonResponse>
|
||||
*/
|
||||
final class QueryAnimeSchedulesCommand extends Data implements DataRequest
|
||||
{
|
||||
use HasRequestFingerprint;
|
||||
|
||||
#[Numeric, Min(1)]
|
||||
public int $page = 1;
|
||||
|
||||
#[IntegerType, Min(1), Nullable]
|
||||
public ?int $limit;
|
||||
|
||||
#[BooleanType]
|
||||
public bool $kids = false;
|
||||
|
||||
#[BooleanType]
|
||||
public bool $sfw = false;
|
||||
|
||||
#[WithCast(EnumCast::class, AnimeScheduleFilterEnum::class)]
|
||||
public ?AnimeScheduleFilterEnum $filter;
|
||||
|
||||
public static function rules(...$args): array
|
||||
{
|
||||
return [
|
||||
"filter" => [new EnumRule(AnimeScheduleFilterEnum::class), new Nullable()]
|
||||
];
|
||||
}
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
public static function fromRequestAndDay(Request $request, ?string $day): self
|
||||
{
|
||||
/**
|
||||
* @var QueryAnimeSchedulesCommand $data
|
||||
*/
|
||||
$data = self::fromRequest($request);
|
||||
|
||||
if (!is_null($day)) {
|
||||
$data->filter = AnimeScheduleFilterEnum::from($day);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
17
app/Dto/QueryMangaRecommendationsCommand.php
Normal file
17
app/Dto/QueryMangaRecommendationsCommand.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use App\Concerns\HasRequestFingerprint;
|
||||
use App\Contracts\DataRequest;
|
||||
use App\Http\Resources\V4\ResultsResource;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
/**
|
||||
* @implements DataRequest<ResultsResource>
|
||||
*/
|
||||
final class QueryMangaRecommendationsCommand extends Data implements DataRequest
|
||||
{
|
||||
use HasRequestFingerprint;
|
||||
}
|
7
app/Dto/QueryMangaReviewsCommand.php
Normal file
7
app/Dto/QueryMangaReviewsCommand.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
final class QueryMangaReviewsCommand extends QueryReviewsCommand
|
||||
{
|
||||
}
|
18
app/Dto/QueryRandomAnimeCommand.php
Normal file
18
app/Dto/QueryRandomAnimeCommand.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @implements DataRequest<AnimeResource>
|
||||
*/
|
||||
final class QueryRandomAnimeCommand extends Data implements DataRequest
|
||||
{
|
||||
#[BooleanType]
|
||||
public bool|Optional $sfw;
|
||||
}
|
14
app/Dto/QueryRandomCharacterCommand.php
Normal file
14
app/Dto/QueryRandomCharacterCommand.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use App\Contracts\DataRequest;
|
||||
use App\Http\Resources\V4\CharacterResource;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
/**
|
||||
* @implements DataRequest<CharacterResource>
|
||||
*/
|
||||
final class QueryRandomCharacterCommand extends Data implements DataRequest
|
||||
{
|
||||
}
|
18
app/Dto/QueryRandomMangaCommand.php
Normal file
18
app/Dto/QueryRandomMangaCommand.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @implements DataRequest<MangaResource>
|
||||
*/
|
||||
final class QueryRandomMangaCommand extends Data implements DataRequest
|
||||
{
|
||||
#[BooleanType]
|
||||
public bool|Optional $sfw;
|
||||
}
|
14
app/Dto/QueryRandomPersonCommand.php
Normal file
14
app/Dto/QueryRandomPersonCommand.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use App\Contracts\DataRequest;
|
||||
use App\Http\Resources\V4\PersonResource;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
/**
|
||||
* @implements DataRequest<PersonResource>
|
||||
*/
|
||||
final class QueryRandomPersonCommand extends Data implements DataRequest
|
||||
{
|
||||
}
|
14
app/Dto/QueryRandomUserCommand.php
Normal file
14
app/Dto/QueryRandomUserCommand.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
use App\Contracts\DataRequest;
|
||||
use App\Http\Resources\V4\ProfileResource;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
/**
|
||||
* @implements DataRequest<ProfileResource>
|
||||
*/
|
||||
final class QueryRandomUserCommand extends Data implements DataRequest
|
||||
{
|
||||
}
|
44
app/Dto/QueryReviewsCommand.php
Normal file
44
app/Dto/QueryReviewsCommand.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Dto;
|
||||
|
||||
|
||||
use App\Casts\EnumCast;
|
||||
use App\Concerns\HasRequestFingerprint;
|
||||
use App\Contracts\DataRequest;
|
||||
use App\Enums\MediaReviewsSortEnum;
|
||||
use App\Http\Resources\V4\ResultsResource;
|
||||
use Spatie\Enum\Laravel\Rules\EnumRule;
|
||||
use Spatie\LaravelData\Attributes\Validation\BooleanType;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @implements DataRequest<ResultsResource>
|
||||
*/
|
||||
abstract class QueryReviewsCommand extends Data implements DataRequest
|
||||
{
|
||||
use HasRequestFingerprint;
|
||||
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
|
||||
#[WithCast(EnumCast::class, MediaReviewsSortEnum::class)]
|
||||
public MediaReviewsSortEnum|Optional $sort;
|
||||
|
||||
#[BooleanType]
|
||||
public bool|Optional $spoilers;
|
||||
|
||||
#[BooleanType]
|
||||
public bool|Optional $preliminary;
|
||||
|
||||
public static function rules(): array
|
||||
{
|
||||
return [
|
||||
"sort" => [new EnumRule(MediaReviewsSortEnum::class)]
|
||||
];
|
||||
}
|
||||
}
|
@ -3,11 +3,15 @@
|
||||
namespace App\Dto;
|
||||
|
||||
use Illuminate\Support\Optional;
|
||||
use Spatie\LaravelData\Attributes\Validation\Min;
|
||||
use Spatie\LaravelData\Attributes\Validation\Numeric;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
abstract class QueryTopItemsCommand extends Data
|
||||
{
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $page;
|
||||
|
||||
#[Numeric, Min(1)]
|
||||
public int|Optional $limit;
|
||||
}
|
||||
|
34
app/Enums/AnimeScheduleFilterEnum.php
Normal file
34
app/Enums/AnimeScheduleFilterEnum.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use Spatie\Enum\Laravel\Enum;
|
||||
|
||||
/**
|
||||
* @method static self monday()
|
||||
* @method static self tuesday()
|
||||
* @method static self wednesday()
|
||||
* @method static self thursday()
|
||||
* @method static self friday()
|
||||
* @method static self saturday()
|
||||
* @method static self sunday()
|
||||
* @method static self other()
|
||||
* @method static self unknown()
|
||||
*/
|
||||
final class AnimeScheduleFilterEnum extends Enum
|
||||
{
|
||||
public function isWeekDay(): bool
|
||||
{
|
||||
return $this->value !== self::other()->value && $this->value !== self::unknown()->value;
|
||||
}
|
||||
|
||||
protected static function labels(): array
|
||||
{
|
||||
return [
|
||||
...collect(self::values())->map(fn ($x) => ucfirst($x))->toArray(),
|
||||
"other" => "Not scheduled once per week",
|
||||
"unknown" => "Unknown"
|
||||
];
|
||||
}
|
||||
}
|
14
app/Enums/ReviewTypeEnum.php
Normal file
14
app/Enums/ReviewTypeEnum.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
|
||||
use Spatie\Enum\Laravel\Enum;
|
||||
|
||||
/**
|
||||
* @method static self anime()
|
||||
* @method static self manga()
|
||||
*/
|
||||
final class ReviewTypeEnum extends Enum
|
||||
{
|
||||
}
|
@ -34,7 +34,7 @@ abstract class ItemLookupHandler extends Data implements RequestHandler
|
||||
$results = $this->scraperService->find($request->id, $requestFingerprint);
|
||||
|
||||
$resource = $this->resource($results->collect());
|
||||
return $this->scraperService->augmentResponse($resource->response(), $requestFingerprint, $results);
|
||||
return $resource->response()->addJikanCacheFlags($requestFingerprint, $results);
|
||||
}
|
||||
|
||||
protected abstract function resource(Collection $results): JsonResource;
|
||||
|
24
app/Features/PersonAnimeLookupHandler.php
Normal file
24
app/Features/PersonAnimeLookupHandler.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\PersonAnimeLookupCommand;
|
||||
use App\Http\Resources\V4\PersonAnimeCollection;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends ItemLookupHandler<PersonAnimeLookupCommand, JsonResponse>
|
||||
*/
|
||||
final class PersonAnimeLookupHandler extends ItemLookupHandler
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return PersonAnimeLookupCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): PersonAnimeCollection
|
||||
{
|
||||
return new PersonAnimeCollection($results->offsetGetFirst("anime_staff_positions"));
|
||||
}
|
||||
}
|
25
app/Features/PersonFullLookupHandler.php
Normal file
25
app/Features/PersonFullLookupHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\PersonFullLookupCommand;
|
||||
use App\Http\Resources\V4\PersonFullResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends ItemLookupHandler<PersonFullLookupCommand, JsonResponse>
|
||||
*/
|
||||
final class PersonFullLookupHandler extends ItemLookupHandler
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return PersonFullLookupCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new PersonFullResource($results->first());
|
||||
}
|
||||
}
|
25
app/Features/PersonLookupHandler.php
Normal file
25
app/Features/PersonLookupHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\PersonLookupCommand;
|
||||
use App\Http\Resources\V4\PersonResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends ItemLookupHandler<PersonLookupCommand, JsonResponse>
|
||||
*/
|
||||
final class PersonLookupHandler extends ItemLookupHandler
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return PersonLookupCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new PersonResource($results->first());
|
||||
}
|
||||
}
|
25
app/Features/PersonMangaLookupHandler.php
Normal file
25
app/Features/PersonMangaLookupHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\PersonMangaLookupCommand;
|
||||
use App\Http\Resources\V4\PersonMangaCollection;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends ItemLookupHandler<PersonMangaLookupCommand, JsonResponse>
|
||||
*/
|
||||
final class PersonMangaLookupHandler extends ItemLookupHandler
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return PersonMangaLookupCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new PersonMangaCollection($results->offsetGetFirst("published_manga"));
|
||||
}
|
||||
}
|
39
app/Features/PersonPicturesLookupHandler.php
Normal file
39
app/Features/PersonPicturesLookupHandler.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\PersonPicturesLookupCommand;
|
||||
use App\Http\Resources\V4\PicturesResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Support\CachedData;
|
||||
use Jikan\MyAnimeList\MalClient;
|
||||
use Jikan\Request\Person\PersonPicturesRequest;
|
||||
|
||||
/**
|
||||
* @extends RequestHandlerWithScraperCache<PersonPicturesLookupCommand, JsonResponse>
|
||||
*/
|
||||
final class PersonPicturesLookupHandler extends RequestHandlerWithScraperCache
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return PersonPicturesLookupCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new PicturesResource($results->first());
|
||||
}
|
||||
|
||||
protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData
|
||||
{
|
||||
$id = $requestParams->get("id");
|
||||
return $this->scraperService->findList(
|
||||
$requestFingerPrint,
|
||||
fn(MalClient $jikan, ?int $page = null) => collect(
|
||||
["pictures" => $jikan->getPersonPictures(new PersonPicturesRequest($id))]
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
25
app/Features/PersonVoicesLookupHandler.php
Normal file
25
app/Features/PersonVoicesLookupHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\PersonVoicesLookupCommand;
|
||||
use App\Http\Resources\V4\PersonVoicesCollection;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends ItemLookupHandler<PersonVoicesLookupCommand, JsonResponse>
|
||||
*/
|
||||
final class PersonVoicesLookupHandler extends ItemLookupHandler
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return PersonVoicesLookupCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new PersonVoicesCollection($results->offsetGetFirst("voice_acting_roles"));
|
||||
}
|
||||
}
|
25
app/Features/ProducerExternalLookupHandler.php
Normal file
25
app/Features/ProducerExternalLookupHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\ProducerExternalLookupCommand;
|
||||
use App\Http\Resources\V4\ExternalLinksResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends ItemLookupHandler<ProducerExternalLookupCommand, JsonResponse>
|
||||
*/
|
||||
final class ProducerExternalLookupHandler extends ItemLookupHandler
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return ProducerExternalLookupCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new ExternalLinksResource($results->first());
|
||||
}
|
||||
}
|
25
app/Features/ProducerFullLookupHandler.php
Normal file
25
app/Features/ProducerFullLookupHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\ProducerFullLookupCommand;
|
||||
use App\Http\Resources\V4\ProducerFullResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends ItemLookupHandler<ProducerFullLookupCommand, JsonResponse>
|
||||
*/
|
||||
final class ProducerFullLookupHandler extends ItemLookupHandler
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return ProducerFullLookupCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new ProducerFullResource($results->first());
|
||||
}
|
||||
}
|
25
app/Features/ProducerLookupHandler.php
Normal file
25
app/Features/ProducerLookupHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\ProducerLookupCommand;
|
||||
use App\Http\Resources\V4\ProducerResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends ItemLookupHandler<ProducerLookupCommand, JsonResponse>
|
||||
*/
|
||||
final class ProducerLookupHandler extends ItemLookupHandler
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return ProducerLookupCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new ProducerResource($results->first());
|
||||
}
|
||||
}
|
22
app/Features/QueryAnimeRecommendationsHandler.php
Normal file
22
app/Features/QueryAnimeRecommendationsHandler.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\QueryAnimeRecommendationsCommand;
|
||||
use Jikan\Helper\Constants;
|
||||
|
||||
/**
|
||||
* @extends QueryRecommendationsHandler<QueryAnimeRecommendationsCommand>
|
||||
*/
|
||||
final class QueryAnimeRecommendationsHandler extends QueryRecommendationsHandler
|
||||
{
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryAnimeRecommendationsCommand::class;
|
||||
}
|
||||
|
||||
protected function recommendationType(): string
|
||||
{
|
||||
return Constants::RECENT_RECOMMENDATION_ANIME;
|
||||
}
|
||||
}
|
25
app/Features/QueryAnimeReviewsHandler.php
Normal file
25
app/Features/QueryAnimeReviewsHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\QueryAnimeReviewsCommand;
|
||||
use App\Enums\ReviewTypeEnum;
|
||||
|
||||
/**
|
||||
* @extends QueryReviewsHandler<QueryAnimeReviewsCommand>
|
||||
*/
|
||||
final class QueryAnimeReviewsHandler extends QueryReviewsHandler
|
||||
{
|
||||
protected function reviewType(): ReviewTypeEnum
|
||||
{
|
||||
return ReviewTypeEnum::anime();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryAnimeReviewsCommand::class;
|
||||
}
|
||||
}
|
50
app/Features/QueryAnimeSchedulesHandler.php
Normal file
50
app/Features/QueryAnimeSchedulesHandler.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Contracts\AnimeRepository;
|
||||
use App\Contracts\RequestHandler;
|
||||
use App\Dto\QueryAnimeSchedulesCommand;
|
||||
use App\Http\Resources\V4\AnimeCollection;
|
||||
use App\Support\CachedData;
|
||||
use Illuminate\Support\Env;
|
||||
|
||||
/**
|
||||
* @implements RequestHandler<QueryAnimeSchedulesCommand, AnimeCollection>
|
||||
*/
|
||||
final class QueryAnimeSchedulesHandler implements RequestHandler
|
||||
{
|
||||
public function __construct(private readonly AnimeRepository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function handle($request)
|
||||
{
|
||||
$limit = intval($request->limit ?? Env::get("MAX_RESULTS_PER_PAGE", 25));
|
||||
$results = $this->repository->getCurrentlyAiring($request->filter, $request->kids, $request->sfw);
|
||||
$results = $results->paginate(
|
||||
$limit,
|
||||
["*"],
|
||||
null,
|
||||
$request->page
|
||||
);
|
||||
|
||||
$animeCollection = new AnimeCollection(
|
||||
$results
|
||||
);
|
||||
$response = $animeCollection->response();
|
||||
|
||||
return $response->addJikanCacheFlags($request->getFingerPrint(), CachedData::from($animeCollection->collection));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryAnimeSchedulesCommand::class;
|
||||
}
|
||||
}
|
25
app/Features/QueryMangaRecommendationsHandler.php
Normal file
25
app/Features/QueryMangaRecommendationsHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\QueryMangaRecommendationsCommand;
|
||||
use Jikan\Helper\Constants;
|
||||
|
||||
/**
|
||||
* @extends QueryRecommendationsHandler<QueryMangaRecommendationsCommand>
|
||||
*/
|
||||
final class QueryMangaRecommendationsHandler extends QueryRecommendationsHandler
|
||||
{
|
||||
protected function recommendationType(): string
|
||||
{
|
||||
return Constants::RECENT_RECOMMENDATION_MANGA;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryMangaRecommendationsCommand::class;
|
||||
}
|
||||
}
|
25
app/Features/QueryMangaReviewsHandler.php
Normal file
25
app/Features/QueryMangaReviewsHandler.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Dto\QueryMangaReviewsCommand;
|
||||
use App\Enums\ReviewTypeEnum;
|
||||
|
||||
/**
|
||||
* @extends QueryReviewsHandler<QueryMangaReviewsCommand>
|
||||
*/
|
||||
final class QueryMangaReviewsHandler extends QueryReviewsHandler
|
||||
{
|
||||
protected function reviewType(): ReviewTypeEnum
|
||||
{
|
||||
return ReviewTypeEnum::manga();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryMangaReviewsCommand::class;
|
||||
}
|
||||
}
|
51
app/Features/QueryRandomAnimeHandler.php
Normal file
51
app/Features/QueryRandomAnimeHandler.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Contracts\AnimeRepository;
|
||||
use App\Contracts\RequestHandler;
|
||||
use App\Dto\QueryRandomAnimeCommand;
|
||||
use App\Http\Resources\V4\AnimeResource;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
/**
|
||||
* @implements RequestHandler<QueryRandomAnimeCommand, AnimeResource>
|
||||
*/
|
||||
final class QueryRandomAnimeHandler implements RequestHandler
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AnimeRepository $repository
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function handle($request): AnimeResource
|
||||
{
|
||||
$sfw = Optional::create() !== $request->sfw ? $request->sfw : null;
|
||||
|
||||
/**
|
||||
* @var Collection $results;
|
||||
*/
|
||||
if ($sfw) {
|
||||
$results = $this->repository->exceptItemsWithAdultRating()->random();
|
||||
} else {
|
||||
$results = $this->repository->random();
|
||||
}
|
||||
|
||||
return new AnimeResource(
|
||||
$results->first()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryRandomAnimeCommand::class;
|
||||
}
|
||||
}
|
33
app/Features/QueryRandomCharacterHandler.php
Normal file
33
app/Features/QueryRandomCharacterHandler.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Contracts\CharacterRepository;
|
||||
use App\Dto\QueryRandomCharacterCommand;
|
||||
use App\Http\Resources\V4\CharacterResource;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends QueryRandomItemHandler<QueryRandomCharacterCommand, CharacterResource>
|
||||
*/
|
||||
final class QueryRandomCharacterHandler extends QueryRandomItemHandler
|
||||
{
|
||||
public function __construct(CharacterRepository $repository)
|
||||
{
|
||||
parent::__construct($repository);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryRandomCharacterCommand::class;
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new CharacterResource($results->first());
|
||||
}
|
||||
}
|
34
app/Features/QueryRandomItemHandler.php
Normal file
34
app/Features/QueryRandomItemHandler.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Contracts\Repository;
|
||||
use App\Contracts\RequestHandler;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Http\Resources\Json\ResourceCollection;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\LaravelData\Data;
|
||||
|
||||
/**
|
||||
* @template TRequest of Data
|
||||
* @template TResponse of ResourceCollection|JsonResource|Response
|
||||
* @implements RequestHandler<TRequest, TResponse>
|
||||
*/
|
||||
abstract class QueryRandomItemHandler implements RequestHandler
|
||||
{
|
||||
protected function __construct(protected readonly Repository $repository)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function handle($request)
|
||||
{
|
||||
$results = $this->repository->random();
|
||||
return $this->resource($results);
|
||||
}
|
||||
|
||||
protected abstract function resource(Collection $results): JsonResource;
|
||||
}
|
51
app/Features/QueryRandomMangaHandler.php
Normal file
51
app/Features/QueryRandomMangaHandler.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Contracts\MangaRepository;
|
||||
use App\Contracts\RequestHandler;
|
||||
use App\Dto\QueryRandomMangaCommand;
|
||||
use App\Http\Resources\V4\MangaResource;
|
||||
use Illuminate\Support\Collection;
|
||||
use Spatie\LaravelData\Optional;
|
||||
|
||||
/**
|
||||
* @implements RequestHandler<QueryRandomMangaCommand, MangaResource>
|
||||
*/
|
||||
final class QueryRandomMangaHandler implements RequestHandler
|
||||
{
|
||||
public function __construct(
|
||||
private readonly MangaRepository $repository
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function handle($request)
|
||||
{
|
||||
$sfw = Optional::create() !== $request->sfw ? $request->sfw : null;
|
||||
|
||||
/**
|
||||
* @var Collection $results;
|
||||
*/
|
||||
if ($sfw) {
|
||||
$results = $this->repository->exceptItemsWithAdultRating()->random();
|
||||
} else {
|
||||
$results = $this->repository->random();
|
||||
}
|
||||
|
||||
return new MangaResource(
|
||||
$results->first()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryRandomMangaCommand::class;
|
||||
}
|
||||
}
|
35
app/Features/QueryRandomPersonHandler.php
Normal file
35
app/Features/QueryRandomPersonHandler.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Contracts\PeopleRepository;
|
||||
use App\Dto\QueryRandomPersonCommand;
|
||||
use App\Http\Resources\V4\PersonResource;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends QueryRandomItemHandler<QueryRandomPersonCommand, PersonResource>
|
||||
*/
|
||||
final class QueryRandomPersonHandler extends QueryRandomItemHandler
|
||||
{
|
||||
public function __construct(PeopleRepository $repository)
|
||||
{
|
||||
parent::__construct($repository);
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new PersonResource(
|
||||
$results->first()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryRandomPersonCommand::class;
|
||||
}
|
||||
}
|
35
app/Features/QueryRandomUserHandler.php
Normal file
35
app/Features/QueryRandomUserHandler.php
Normal file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Contracts\UserRepository;
|
||||
use App\Dto\QueryRandomUserCommand;
|
||||
use App\Http\Resources\V4\ProfileResource;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* @extends QueryRandomItemHandler<QueryRandomUserCommand, ProfileResource>
|
||||
*/
|
||||
final class QueryRandomUserHandler extends QueryRandomItemHandler
|
||||
{
|
||||
public function __construct(UserRepository $repository)
|
||||
{
|
||||
parent::__construct($repository);
|
||||
}
|
||||
|
||||
protected function resource(Collection $results): JsonResource
|
||||
{
|
||||
return new ProfileResource(
|
||||
$results->first()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function requestClass(): string
|
||||
{
|
||||
return QueryRandomUserCommand::class;
|
||||
}
|
||||
}
|
30
app/Features/QueryRecommendationsHandler.php
Normal file
30
app/Features/QueryRecommendationsHandler.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Contracts\DataRequest;
|
||||
use App\Http\Resources\V4\ResultsResource;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Support\CachedData;
|
||||
use Jikan\MyAnimeList\MalClient;
|
||||
use Jikan\Request\Recommendations\RecentRecommendationsRequest;
|
||||
|
||||
/**
|
||||
* @template TRequest of DataRequest<ResultsResource>
|
||||
* @extends RequestHandlerWithScraperCache<TRequest, ResultsResource>
|
||||
*/
|
||||
abstract class QueryRecommendationsHandler extends RequestHandlerWithScraperCache
|
||||
{
|
||||
protected abstract function recommendationType(): string;
|
||||
|
||||
protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData
|
||||
{
|
||||
return $this->scraperService->findList(
|
||||
$requestFingerPrint,
|
||||
fn(MalClient $jikan, ?int $page = null) => $jikan->getRecentRecommendations(new RecentRecommendationsRequest(
|
||||
$this->recommendationType(), $page
|
||||
)),
|
||||
$requestParams->get("page", 1)
|
||||
);
|
||||
}
|
||||
}
|
42
app/Features/QueryReviewsHandler.php
Normal file
42
app/Features/QueryReviewsHandler.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Features;
|
||||
|
||||
use App\Contracts\DataRequest;
|
||||
use App\Enums\ReviewTypeEnum;
|
||||
use App\Features\Concerns\ResolvesMediaReviewParams;
|
||||
use App\Http\Resources\V4\ResultsResource;
|
||||
use Illuminate\Support\Collection;
|
||||
use App\Support\CachedData;
|
||||
use Jikan\MyAnimeList\MalClient;
|
||||
use Jikan\Request\Reviews\ReviewsRequest;
|
||||
|
||||
/**
|
||||
* @template TRequest of DataRequest<ResultsResource>
|
||||
* @extends RequestHandlerWithScraperCache<TRequest, ResultsResource>
|
||||
*/
|
||||
abstract class QueryReviewsHandler extends RequestHandlerWithScraperCache
|
||||
{
|
||||
use ResolvesMediaReviewParams;
|
||||
|
||||
protected abstract function reviewType(): ReviewTypeEnum;
|
||||
|
||||
protected function getScraperData(string $requestFingerPrint, Collection $requestParams): CachedData
|
||||
{
|
||||
$reviewRequestParams = $this->getReviewRequestParams($requestParams);
|
||||
extract($reviewRequestParams);
|
||||
|
||||
return $this->scraperService->findList(
|
||||
$requestFingerPrint,
|
||||
fn(MalClient $jikan, ?int $page = null) => $jikan->getReviews(
|
||||
new ReviewsRequest(
|
||||
$this->reviewType()->value,
|
||||
$page,
|
||||
$sort,
|
||||
$spoilers,
|
||||
$preliminary
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -53,6 +53,6 @@ abstract class RequestHandlerWithScraperCache implements RequestHandler
|
||||
{
|
||||
$finalResults = $results->collect();
|
||||
$response = $this->resource($finalResults)->response();
|
||||
return $this->scraperService->augmentResponse($response, $requestFingerPrint, $results);
|
||||
return $response->addJikanCacheFlags($requestFingerPrint, $results);
|
||||
}
|
||||
}
|
||||
|
@ -2,22 +2,13 @@
|
||||
|
||||
namespace App\Http\Controllers\V4DB;
|
||||
|
||||
use App\Character;
|
||||
use App\Http\HttpHelper;
|
||||
use App\Http\HttpResponse;
|
||||
use App\Http\Resources\V4\PersonAnimeCollection;
|
||||
use App\Http\Resources\V4\PersonAnimeResource;
|
||||
use App\Http\Resources\V4\PersonMangaCollection;
|
||||
use App\Http\Resources\V4\PersonVoiceResource;
|
||||
use App\Http\Resources\V4\PersonVoicesCollection;
|
||||
use App\Http\Resources\V4\PicturesResource;
|
||||
use App\Person;
|
||||
use App\Dto\PersonAnimeLookupCommand;
|
||||
use App\Dto\PersonFullLookupCommand;
|
||||
use App\Dto\PersonLookupCommand;
|
||||
use App\Dto\PersonMangaLookupCommand;
|
||||
use App\Dto\PersonPicturesLookupCommand;
|
||||
use App\Dto\PersonVoicesLookupCommand;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Jikan\Request\Character\CharacterPicturesRequest;
|
||||
use Jikan\Request\Person\PersonRequest;
|
||||
use Jikan\Request\Person\PersonPicturesRequest;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
|
||||
class PersonController extends Controller
|
||||
{
|
||||
@ -53,59 +44,8 @@ class PersonController extends Controller
|
||||
*/
|
||||
public function full(Request $request, int $id)
|
||||
{
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
|
||||
if (
|
||||
$results->isEmpty()
|
||||
|| $this->isExpired($request, $results)
|
||||
) {
|
||||
$response = Person::scrape($id);
|
||||
|
||||
if (HttpHelper::hasError($response)) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
$meta = [
|
||||
'createdAt' => new UTCDateTime(),
|
||||
'modifiedAt' => new UTCDateTime(),
|
||||
'request_hash' => $this->fingerprint
|
||||
];
|
||||
}
|
||||
$meta['modifiedAt'] = new UTCDateTime();
|
||||
|
||||
$response = $meta + $response;
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
Person::create($response);
|
||||
}
|
||||
|
||||
if ($this->isExpired($request, $results)) {
|
||||
Person::query()
|
||||
->where('mal_id', $id)
|
||||
->update($response);
|
||||
}
|
||||
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
$response = (new \App\Http\Resources\V4\PersonFullResource(
|
||||
$results->first()
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = PersonFullLookupCommand::from($request, $id);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,59 +80,8 @@ class PersonController extends Controller
|
||||
*/
|
||||
public function main(Request $request, int $id)
|
||||
{
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
|
||||
if (
|
||||
$results->isEmpty()
|
||||
|| $this->isExpired($request, $results)
|
||||
) {
|
||||
$response = Person::scrape($id);
|
||||
|
||||
if (HttpHelper::hasError($response)) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
$meta = [
|
||||
'createdAt' => new UTCDateTime(),
|
||||
'modifiedAt' => new UTCDateTime(),
|
||||
'request_hash' => $this->fingerprint
|
||||
];
|
||||
}
|
||||
$meta['modifiedAt'] = new UTCDateTime();
|
||||
|
||||
$response = $meta + $response;
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
Person::create($response);
|
||||
}
|
||||
|
||||
if ($this->isExpired($request, $results)) {
|
||||
Person::query()
|
||||
->where('mal_id', $id)
|
||||
->update($response);
|
||||
}
|
||||
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
$response = (new \App\Http\Resources\V4\PersonResource(
|
||||
$results->first()
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = PersonLookupCommand::from($request, $id);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -221,59 +110,8 @@ class PersonController extends Controller
|
||||
*/
|
||||
public function anime(Request $request, int $id)
|
||||
{
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
|
||||
if (
|
||||
$results->isEmpty()
|
||||
|| $this->isExpired($request, $results)
|
||||
) {
|
||||
$response = Person::scrape($id);
|
||||
|
||||
if (HttpHelper::hasError($response)) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
$meta = [
|
||||
'createdAt' => new UTCDateTime(),
|
||||
'modifiedAt' => new UTCDateTime(),
|
||||
'request_hash' => $this->fingerprint
|
||||
];
|
||||
}
|
||||
$meta['modifiedAt'] = new UTCDateTime();
|
||||
|
||||
$response = $meta + $response;
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
Person::create($response);
|
||||
}
|
||||
|
||||
if ($this->isExpired($request, $results)) {
|
||||
Person::query()
|
||||
->where('mal_id', $id)
|
||||
->update($response);
|
||||
}
|
||||
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
$response = (new PersonAnimeCollection(
|
||||
$results->first()['anime_staff_positions']
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = PersonAnimeLookupCommand::from($request, $id);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -302,59 +140,8 @@ class PersonController extends Controller
|
||||
*/
|
||||
public function voices(Request $request, int $id)
|
||||
{
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
|
||||
if (
|
||||
$results->isEmpty()
|
||||
|| $this->isExpired($request, $results)
|
||||
) {
|
||||
$response = Person::scrape($id);
|
||||
|
||||
if (HttpHelper::hasError($response)) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
$meta = [
|
||||
'createdAt' => new UTCDateTime(),
|
||||
'modifiedAt' => new UTCDateTime(),
|
||||
'request_hash' => $this->fingerprint
|
||||
];
|
||||
}
|
||||
$meta['modifiedAt'] = new UTCDateTime();
|
||||
|
||||
$response = $meta + $response;
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
Person::create($response);
|
||||
}
|
||||
|
||||
if ($this->isExpired($request, $results)) {
|
||||
Person::query()
|
||||
->where('mal_id', $id)
|
||||
->update($response);
|
||||
}
|
||||
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
$response = (new PersonVoicesCollection(
|
||||
$results->first()['voice_acting_roles']
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = PersonVoicesLookupCommand::from($request, $id);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -383,59 +170,8 @@ class PersonController extends Controller
|
||||
*/
|
||||
public function manga(Request $request, int $id)
|
||||
{
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
|
||||
if (
|
||||
$results->isEmpty()
|
||||
|| $this->isExpired($request, $results)
|
||||
) {
|
||||
$response = Person::scrape($id);
|
||||
|
||||
if (HttpHelper::hasError($response)) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
$meta = [
|
||||
'createdAt' => new UTCDateTime(),
|
||||
'modifiedAt' => new UTCDateTime(),
|
||||
'request_hash' => $this->fingerprint
|
||||
];
|
||||
}
|
||||
$meta['modifiedAt'] = new UTCDateTime();
|
||||
|
||||
$response = $meta + $response;
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
Person::create($response);
|
||||
}
|
||||
|
||||
if ($this->isExpired($request, $results)) {
|
||||
Person::query()
|
||||
->where('mal_id', $id)
|
||||
->update($response);
|
||||
}
|
||||
|
||||
$results = Person::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
$response = (new PersonMangaCollection(
|
||||
$results->first()['published_manga']
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = PersonMangaLookupCommand::from($request, $id);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -480,28 +216,7 @@ class PersonController extends Controller
|
||||
*/
|
||||
public function pictures(Request $request, int $id)
|
||||
{
|
||||
$results = DB::table($this->getRouteTable($request))
|
||||
->where('request_hash', $this->fingerprint)
|
||||
->get();
|
||||
|
||||
if (
|
||||
$results->isEmpty()
|
||||
|| $this->isExpired($request, $results)
|
||||
) {
|
||||
$person = ['pictures' => $this->jikan->getPersonPictures(new PersonPicturesRequest($id))];
|
||||
$response = \json_decode($this->serializer->serialize($person, 'json'), true);
|
||||
|
||||
$results = $this->updateCache($request, $results, $response);
|
||||
}
|
||||
|
||||
$response = (new PicturesResource(
|
||||
$results->first()
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = PersonPicturesLookupCommand::from($request, $id);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
}
|
||||
|
@ -2,19 +2,12 @@
|
||||
|
||||
namespace App\Http\Controllers\V4DB;
|
||||
|
||||
use App\Anime;
|
||||
use App\Http\Resources\V4\ExternalLinksResource;
|
||||
use App\Producers;
|
||||
use App\Http\HttpHelper;
|
||||
use App\Http\HttpResponse;
|
||||
use App\Http\QueryBuilder\SearchQueryBuilderProducer;
|
||||
use App\Http\Resources\V4\AnimeCollection;
|
||||
use App\Http\Resources\V4\ProducerCollection;
|
||||
use App\Dto\ProducerExternalLookupCommand;
|
||||
use App\Dto\ProducerFullLookupCommand;
|
||||
use App\Dto\ProducerLookupCommand;
|
||||
use Illuminate\Http\Request;
|
||||
use Jikan\Model\Producer\Producer;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
|
||||
class ProducerController extends ControllerWithQueryBuilderProvider
|
||||
class ProducerController extends Controller
|
||||
{
|
||||
/**
|
||||
* @OA\Get(
|
||||
@ -47,60 +40,8 @@ class ProducerController extends ControllerWithQueryBuilderProvider
|
||||
*/
|
||||
public function main(Request $request, int $id)
|
||||
{
|
||||
$results = Producers::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
|
||||
if (
|
||||
$results->isEmpty()
|
||||
|| $this->isExpired($request, $results)
|
||||
) {
|
||||
$response = Producers::scrape($id);
|
||||
|
||||
if (HttpHelper::hasError($response)) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
$meta = [
|
||||
'createdAt' => new UTCDateTime(),
|
||||
'modifiedAt' => new UTCDateTime(),
|
||||
'request_hash' => $this->fingerprint
|
||||
];
|
||||
}
|
||||
$meta['modifiedAt'] = new UTCDateTime();
|
||||
|
||||
$response = $meta + $response;
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
Producers::query()
|
||||
->insert($response);
|
||||
}
|
||||
|
||||
if ($this->isExpired($request, $results)) {
|
||||
Producers::query()
|
||||
->where('mal_id', $id)
|
||||
->update($response);
|
||||
}
|
||||
|
||||
$results = Producers::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
$response = (new \App\Http\Resources\V4\ProducerResource(
|
||||
$results->first()
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = ProducerLookupCommand::from($request, $id);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -134,60 +75,8 @@ class ProducerController extends ControllerWithQueryBuilderProvider
|
||||
*/
|
||||
public function full(Request $request, int $id)
|
||||
{
|
||||
$results = Producers::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
|
||||
if (
|
||||
$results->isEmpty()
|
||||
|| $this->isExpired($request, $results)
|
||||
) {
|
||||
$response = Producers::scrape($id);
|
||||
|
||||
if (HttpHelper::hasError($response)) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
$meta = [
|
||||
'createdAt' => new UTCDateTime(),
|
||||
'modifiedAt' => new UTCDateTime(),
|
||||
'request_hash' => $this->fingerprint
|
||||
];
|
||||
}
|
||||
$meta['modifiedAt'] = new UTCDateTime();
|
||||
|
||||
$response = $meta + $response;
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
Producers::query()
|
||||
->insert($response);
|
||||
}
|
||||
|
||||
if ($this->isExpired($request, $results)) {
|
||||
Producers::query()
|
||||
->where('mal_id', $id)
|
||||
->update($response);
|
||||
}
|
||||
|
||||
$results = Producers::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
$response = (new \App\Http\Resources\V4\ProducerFullResource(
|
||||
$results->first()
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = ProducerFullLookupCommand::from($request, $id);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -218,59 +107,7 @@ class ProducerController extends ControllerWithQueryBuilderProvider
|
||||
*/
|
||||
public function external(Request $request, int $id)
|
||||
{
|
||||
$results = Producers::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
|
||||
if (
|
||||
$results->isEmpty()
|
||||
|| $this->isExpired($request, $results)
|
||||
) {
|
||||
$response = Producers::scrape($id);
|
||||
|
||||
if (HttpHelper::hasError($response)) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
$meta = [
|
||||
'createdAt' => new UTCDateTime(),
|
||||
'modifiedAt' => new UTCDateTime(),
|
||||
'request_hash' => $this->fingerprint
|
||||
];
|
||||
}
|
||||
$meta['modifiedAt'] = new UTCDateTime();
|
||||
|
||||
$response = $meta + $response;
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
Producers::query()
|
||||
->insert($response);
|
||||
}
|
||||
|
||||
if ($this->isExpired($request, $results)) {
|
||||
Producers::query()
|
||||
->where('mal_id', $id)
|
||||
->update($response);
|
||||
}
|
||||
|
||||
$results = Producers::query()
|
||||
->where('mal_id', $id)
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($results->isEmpty()) {
|
||||
return HttpResponse::notFound($request);
|
||||
}
|
||||
|
||||
$response = (new ExternalLinksResource(
|
||||
$results->first()
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = ProducerExternalLookupCommand::from($request, $id);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,11 @@ namespace App\Http\Controllers\V4DB;
|
||||
|
||||
use App\Anime;
|
||||
use App\Character;
|
||||
use App\Dto\QueryRandomAnimeCommand;
|
||||
use App\Dto\QueryRandomCharacterCommand;
|
||||
use App\Dto\QueryRandomMangaCommand;
|
||||
use App\Dto\QueryRandomPersonCommand;
|
||||
use App\Dto\QueryRandomUserCommand;
|
||||
use App\Http\HttpHelper;
|
||||
use App\Http\HttpResponse;
|
||||
use App\Http\Resources\V4\AnimeCollection;
|
||||
@ -72,23 +77,9 @@ class RandomController extends Controller
|
||||
* ),
|
||||
* ),
|
||||
*/
|
||||
public function anime(Request $request)
|
||||
public function anime(QueryRandomAnimeCommand $command)
|
||||
{
|
||||
$sfw = $request->get('sfw');
|
||||
|
||||
$results = Anime::query();
|
||||
|
||||
if (!is_null($sfw)) {
|
||||
$results = $results
|
||||
->where('rating', '!=', 'Rx - Hentai');
|
||||
}
|
||||
|
||||
$results = $results
|
||||
->raw(fn($collection) => $collection->aggregate([ ['$sample' => ['size' => 1]] ]));
|
||||
|
||||
return new AnimeResource(
|
||||
$results->first()
|
||||
);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,24 +104,9 @@ class RandomController extends Controller
|
||||
* ),
|
||||
* ),
|
||||
*/
|
||||
public function manga(Request $request)
|
||||
public function manga(QueryRandomMangaCommand $command)
|
||||
{
|
||||
$sfw = $request->get('sfw');
|
||||
|
||||
|
||||
$results = Manga::query();
|
||||
|
||||
if (!is_null($sfw)) {
|
||||
$results = $results
|
||||
->where('type', '!=', 'Doujinshi');
|
||||
}
|
||||
|
||||
$results = $results
|
||||
->raw(fn($collection) => $collection->aggregate([ ['$sample' => ['size' => 1]] ]));
|
||||
|
||||
return new MangaResource(
|
||||
$results->first()
|
||||
);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -155,14 +131,9 @@ class RandomController extends Controller
|
||||
* ),
|
||||
* ),
|
||||
*/
|
||||
public function characters(Request $request)
|
||||
public function characters(QueryRandomCharacterCommand $command)
|
||||
{
|
||||
$results = Character::query()
|
||||
->raw(fn($collection) => $collection->aggregate([ ['$sample' => ['size' => 1]] ]));
|
||||
|
||||
return new CharacterResource(
|
||||
$results->first()
|
||||
);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -187,14 +158,9 @@ class RandomController extends Controller
|
||||
* ),
|
||||
* ),
|
||||
*/
|
||||
public function people(Request $request)
|
||||
public function people(QueryRandomPersonCommand $command)
|
||||
{
|
||||
$results = Person::query()
|
||||
->raw(fn($collection) => $collection->aggregate([ ['$sample' => ['size' => 1]] ]));
|
||||
|
||||
return new PersonResource(
|
||||
$results->first()
|
||||
);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -219,13 +185,8 @@ class RandomController extends Controller
|
||||
* ),
|
||||
* ),
|
||||
*/
|
||||
public function users(Request $request)
|
||||
public function users(QueryRandomUserCommand $command)
|
||||
{
|
||||
$results = Profile::query()
|
||||
->raw(fn($collection) => $collection->aggregate([ ['$sample' => ['size' => 1]] ]));
|
||||
|
||||
return new ProfileResource(
|
||||
$results->first()
|
||||
);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers\V4DB;
|
||||
|
||||
use App\Http\HttpHelper;
|
||||
use App\Http\HttpResponse;
|
||||
use App\Http\Resources\V4\ResultsResource;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Jikan\Helper\Constants;
|
||||
use Jikan\Request\Recommendations\RecentRecommendationsRequest;
|
||||
use Jikan\Request\Reviews\RecentReviewsRequest;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
use App\Dto\QueryAnimeRecommendationsCommand;
|
||||
use App\Dto\QueryMangaRecommendationsCommand;
|
||||
|
||||
class RecommendationsController extends Controller
|
||||
{
|
||||
@ -37,33 +30,9 @@ class RecommendationsController extends Controller
|
||||
* ),
|
||||
*
|
||||
*/
|
||||
public function anime(Request $request)
|
||||
public function anime(QueryAnimeRecommendationsCommand $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;
|
||||
$anime = $this->jikan->getRecentRecommendations(new RecentRecommendationsRequest(Constants::RECENT_RECOMMENDATION_ANIME, $page));
|
||||
$response = \json_decode($this->serializer->serialize($anime, '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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,31 +57,8 @@ class RecommendationsController extends Controller
|
||||
* ),
|
||||
*
|
||||
*/
|
||||
public function manga(Request $request)
|
||||
public function manga(QueryMangaRecommendationsCommand $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;
|
||||
$anime = $this->jikan->getRecentRecommendations(new RecentRecommendationsRequest(Constants::RECENT_RECOMMENDATION_MANGA, $page));
|
||||
$response = \json_decode($this->serializer->serialize($anime, '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);
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers\V4DB;
|
||||
|
||||
use App\Http\HttpHelper;
|
||||
use App\Http\HttpResponse;
|
||||
use App\Http\Resources\V4\ResultsResource;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Jikan\Helper\Constants;
|
||||
use Jikan\Request\Reviews\RecentReviewsRequest;
|
||||
use Jikan\Request\Reviews\ReviewsRequest;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use App\Dto\QueryAnimeReviewsCommand;
|
||||
use App\Dto\QueryMangaReviewsCommand;
|
||||
|
||||
class ReviewsController extends Controller
|
||||
{
|
||||
@ -63,52 +55,9 @@ class ReviewsController extends Controller
|
||||
* ),
|
||||
* ),
|
||||
*/
|
||||
public function anime(Request $request)
|
||||
public function anime(QueryAnimeReviewsCommand $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;
|
||||
$sort = $request->get('sort') ?? Constants::REVIEWS_SORT_MOST_VOTED;
|
||||
|
||||
if (!in_array($sort, [Constants::REVIEWS_SORT_MOST_VOTED, Constants::REVIEWS_SORT_NEWEST, Constants::REVIEWS_SORT_OLDEST])) {
|
||||
throw new BadRequestException('Invalid sort for reviews. Please refer to the documentation: https://docs.api.jikan.moe/');
|
||||
}
|
||||
|
||||
$spoilers = $request->get('spoilers') ?? false;
|
||||
$preliminary = $request->get('preliminary') ?? false;
|
||||
|
||||
$anime = $this->jikan
|
||||
->getReviews(
|
||||
new ReviewsRequest(
|
||||
Constants::ANIME,
|
||||
$page,
|
||||
$sort,
|
||||
$spoilers,
|
||||
$preliminary
|
||||
)
|
||||
);
|
||||
|
||||
$response = \json_decode($this->serializer->serialize($anime, '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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -159,49 +108,8 @@ class ReviewsController extends Controller
|
||||
* ),
|
||||
* ),
|
||||
*/
|
||||
public function manga(Request $request)
|
||||
public function manga(QueryMangaReviewsCommand $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;
|
||||
$sort = $request->get('sort') ?? Constants::REVIEWS_SORT_MOST_VOTED;
|
||||
|
||||
if (!in_array($sort, [Constants::REVIEWS_SORT_MOST_VOTED, Constants::REVIEWS_SORT_NEWEST, Constants::REVIEWS_SORT_OLDEST])) {
|
||||
throw new BadRequestException('Invalid sort for reviews. Please refer to the documentation: https://docs.api.jikan.moe/');
|
||||
}
|
||||
|
||||
$spoilers = $request->get('spoilers') ?? false;
|
||||
$preliminary = $request->get('preliminary') ?? false;
|
||||
|
||||
$anime = $this->jikan
|
||||
->getReviews(
|
||||
new ReviewsRequest(
|
||||
Constants::MANGA,
|
||||
$page,
|
||||
$sort,
|
||||
$spoilers,
|
||||
$preliminary
|
||||
)
|
||||
);
|
||||
|
||||
$response = \json_decode($this->serializer->serialize($anime, '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);
|
||||
}
|
||||
}
|
||||
|
@ -2,44 +2,11 @@
|
||||
|
||||
namespace App\Http\Controllers\V4DB;
|
||||
|
||||
use App\Anime;
|
||||
use App\Http\HttpResponse;
|
||||
use App\Http\Resources\V4\AnimeCollection;
|
||||
use App\Http\Resources\V4\AnimeResource;
|
||||
use App\Http\Resources\V4\CommonResource;
|
||||
use App\Http\Resources\V4\ScheduleResource;
|
||||
use App\Dto\QueryAnimeSchedulesCommand;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Jikan\Helper\Constants;
|
||||
use Jikan\Request\Schedule\ScheduleRequest;
|
||||
|
||||
class ScheduleController extends Controller
|
||||
{
|
||||
private const VALID_FILTERS = [
|
||||
'monday',
|
||||
'tuesday',
|
||||
'wednesday',
|
||||
'thursday',
|
||||
'friday',
|
||||
'saturday',
|
||||
'sunday',
|
||||
'other',
|
||||
'unknown',
|
||||
];
|
||||
|
||||
private const VALID_DAYS = [
|
||||
'monday',
|
||||
'tuesday',
|
||||
'wednesday',
|
||||
'thursday',
|
||||
'friday',
|
||||
'saturday',
|
||||
'sunday',
|
||||
];
|
||||
|
||||
private $request;
|
||||
private $day;
|
||||
|
||||
/**
|
||||
* @OA\Get(
|
||||
* path="/schedules",
|
||||
@ -107,92 +74,9 @@ class ScheduleController extends Controller
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
/*
|
||||
* all have status as currently airing
|
||||
* all have premiered but they're not necesarily the current season or year
|
||||
* all have aired date but they're not necessarily the current date/season
|
||||
*
|
||||
*/
|
||||
public function main(Request $request, ?string $day = null)
|
||||
{
|
||||
$this->request = $request;
|
||||
|
||||
$page = $this->request->get('page') ?? 1;
|
||||
$limit = $this->request->get('limit') ?? env('MAX_RESULTS_PER_PAGE', 25);
|
||||
$filter = $this->request->get('filter') ?? null;
|
||||
$kids = $this->request->get('kids') ?? false;
|
||||
$sfw = $this->request->get('sfw') ?? false;
|
||||
|
||||
if (!is_null($day)) {
|
||||
$this->day = strtolower($day);
|
||||
}
|
||||
|
||||
if (!is_null($filter) && is_null($day)) {
|
||||
$this->day = strtolower($filter);
|
||||
}
|
||||
|
||||
if (null !== $this->day
|
||||
&& !\in_array($this->day, self::VALID_FILTERS, true)) {
|
||||
return HttpResponse::badRequest($this->request);
|
||||
}
|
||||
|
||||
$results = Anime::query()
|
||||
->orderBy('members')
|
||||
->where('type', 'TV')
|
||||
->where('status', 'Currently Airing')
|
||||
;
|
||||
|
||||
if ($kids) {
|
||||
$results = $results
|
||||
->orWhere('demographics.mal_id', '!=', Constants::GENRE_ANIME_KIDS);
|
||||
}
|
||||
|
||||
if ($sfw) {
|
||||
$results = $results
|
||||
->orWhere('demographics.mal_id', '!=', Constants::GENRE_ANIME_HENTAI);
|
||||
}
|
||||
|
||||
// if (is_null($sfw)) {
|
||||
// $results = $results
|
||||
// ->orWhere('genres.mal_id', '!=', Constants::GENRE_ANIME_HENTAI)
|
||||
// ->orWhere('genres.mal_id', '!=', Constants::GENRE_ANIME_BOYS_LOVE)
|
||||
// ->orWhere('genres.mal_id', '!=', Constants::GENRE_ANIME_GIRLS_LOVE)
|
||||
// ;
|
||||
// }
|
||||
|
||||
if (\in_array($this->day, self::VALID_DAYS)) {
|
||||
$this->day = ucfirst($this->day);
|
||||
|
||||
$results
|
||||
->where('broadcast', 'like', "{$this->day}%");
|
||||
}
|
||||
|
||||
if ($this->day === 'unknown') {
|
||||
$results
|
||||
->where('broadcast', 'Unknown');
|
||||
}
|
||||
|
||||
if ($this->day === 'other') {
|
||||
$results
|
||||
->where('broadcast', 'Not scheduled once per week');
|
||||
}
|
||||
|
||||
$results = $results
|
||||
->paginate(
|
||||
intval($limit),
|
||||
['*'],
|
||||
null,
|
||||
$page
|
||||
);
|
||||
|
||||
$response = (new AnimeCollection(
|
||||
$results
|
||||
))->response();
|
||||
|
||||
return $this->prepareResponse(
|
||||
$response,
|
||||
$results,
|
||||
$request
|
||||
);
|
||||
$command = QueryAnimeSchedulesCommand::from($request, $day);
|
||||
return $this->mediator->send($command);
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
namespace App;
|
||||
|
||||
use App\Filters\FilterQueryString;
|
||||
use Illuminate\Support\Collection;
|
||||
use Jenssegers\Mongodb\Eloquent\Builder;
|
||||
|
||||
class JikanApiModel extends \Jenssegers\Mongodb\Eloquent\Model
|
||||
{
|
||||
@ -15,4 +17,12 @@ class JikanApiModel extends \Jenssegers\Mongodb\Eloquent\Model
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $filters = [];
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
public function scopeRandom(Builder $query, int $numberOfRandomItems = 1): Collection
|
||||
{
|
||||
return $query->raw(fn(\MongoDB\Collection $collection) => $collection->aggregate([
|
||||
['$sample' => ['size' => $numberOfRandomItems]]
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
30
app/Macros/ResponseJikanCacheFlags.php
Normal file
30
app/Macros/ResponseJikanCacheFlags.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Macros;
|
||||
|
||||
use App\Concerns\ScraperCacheTtl;
|
||||
use App\Support\CachedData;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* @mixin Response
|
||||
*/
|
||||
final class ResponseJikanCacheFlags
|
||||
{
|
||||
use ScraperCacheTtl;
|
||||
|
||||
public function __invoke(): \Closure
|
||||
{
|
||||
return function (string $cacheKey, CachedData $scraperResults) {
|
||||
/**
|
||||
* @var Response $this
|
||||
*/
|
||||
return $this
|
||||
->header("X-Request-Fingerprint", $cacheKey)
|
||||
->setTtl(self::cacheTtl())
|
||||
->setExpires(Carbon::createFromTimestamp($scraperResults->expiry()))
|
||||
->setLastModified(Carbon::createFromTimestamp($scraperResults->lastModified()));
|
||||
};
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ use App\Http\QueryBuilder\MangaSearchQueryBuilder;
|
||||
use App\Http\QueryBuilder\TopAnimeQueryBuilder;
|
||||
use App\Http\QueryBuilder\TopMangaQueryBuilder;
|
||||
use App\Macros\CollectionOffsetGetFirst;
|
||||
use App\Macros\ResponseJikanCacheFlags;
|
||||
use App\Macros\To2dArrayWithDottedKeys;
|
||||
use App\Magazine;
|
||||
use App\Mixins\ScoutBuilderMixin;
|
||||
@ -54,6 +55,7 @@ use App\Support\DefaultMediator;
|
||||
use App\Support\JikanUnitOfWork;
|
||||
use Illuminate\Contracts\Container\BindingResolutionException;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Env;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Support\Collection;
|
||||
@ -307,7 +309,20 @@ class AppServiceProvider extends ServiceProvider
|
||||
Features\MangaLookupHandler::class => $unitOfWorkInstance->manga(),
|
||||
Features\MangaFullLookupHandler::class => $unitOfWorkInstance->manga(),
|
||||
Features\MangaRelationsLookupHandler::class => $unitOfWorkInstance->manga(),
|
||||
Features\MangaExternalLookupHandler::class => $unitOfWorkInstance->manga()
|
||||
Features\MangaExternalLookupHandler::class => $unitOfWorkInstance->manga(),
|
||||
Features\PersonLookupHandler::class => $unitOfWorkInstance->people(),
|
||||
Features\PersonAnimeLookupHandler::class => $unitOfWorkInstance->people(),
|
||||
Features\PersonFullLookupHandler::class => $unitOfWorkInstance->people(),
|
||||
Features\PersonMangaLookupHandler::class => $unitOfWorkInstance->people(),
|
||||
Features\PersonVoicesLookupHandler::class => $unitOfWorkInstance->people(),
|
||||
Features\PersonPicturesLookupHandler::class => $unitOfWorkInstance->documents("people_pictures"),
|
||||
Features\ProducerLookupHandler::class => $unitOfWorkInstance->producers(),
|
||||
Features\ProducerFullLookupHandler::class => $unitOfWorkInstance->producers(),
|
||||
Features\ProducerExternalLookupHandler::class => $unitOfWorkInstance->producers(),
|
||||
Features\QueryAnimeRecommendationsHandler::class => $unitOfWorkInstance->documents("recommendations"),
|
||||
Features\QueryMangaRecommendationsHandler::class => $unitOfWorkInstance->documents("recommendations"),
|
||||
Features\QueryAnimeReviewsHandler::class => $unitOfWorkInstance->documents("reviews"),
|
||||
Features\QueryMangaReviewsHandler::class => $unitOfWorkInstance->documents("reviews")
|
||||
];
|
||||
|
||||
foreach ($requestHandlersWithScraperService as $handlerClass => $repositoryInstance) {
|
||||
@ -319,7 +334,14 @@ class AppServiceProvider extends ServiceProvider
|
||||
]);
|
||||
}
|
||||
|
||||
// automatically resolvable dependencies or no dependencies at all
|
||||
$requestHandlersWithNoDependencies = [
|
||||
Features\QueryRandomAnimeHandler::class,
|
||||
Features\QueryRandomMangaHandler::class,
|
||||
Features\QueryRandomCharacterHandler::class,
|
||||
Features\QueryRandomPersonHandler::class,
|
||||
Features\QueryRandomUserHandler::class,
|
||||
Features\QueryAnimeSchedulesHandler::class
|
||||
];
|
||||
|
||||
foreach ($requestHandlersWithNoDependencies as $handlerClass) {
|
||||
@ -372,6 +394,8 @@ class AppServiceProvider extends ServiceProvider
|
||||
->reject(fn ($class, $macro) => Collection::hasMacro($macro))
|
||||
->each(fn ($class, $macro) => Collection::macro($macro, app($class)()));
|
||||
|
||||
Response::macro("addJikanCacheFlags", app(ResponseJikanCacheFlags::class)());
|
||||
|
||||
ScoutBuilder::mixin(new ScoutBuilderMixin());
|
||||
}
|
||||
|
||||
|
@ -55,4 +55,9 @@ class DatabaseRepository extends RepositoryQuery implements Repository
|
||||
{
|
||||
return $this->queryable(true)->insert($attributes);
|
||||
}
|
||||
|
||||
public function random(int $numberOfRandomItems = 1): Collection
|
||||
{
|
||||
return $this->queryable(true)->random($numberOfRandomItems);
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,11 @@ use App\Anime;
|
||||
use App\Contracts\AnimeRepository;
|
||||
use App\Contracts\Repository;
|
||||
use App\Enums\AnimeRatingEnum;
|
||||
use App\Enums\AnimeScheduleFilterEnum;
|
||||
use App\Enums\AnimeStatusEnum;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use App\Enums\AnimeTypeEnum;
|
||||
use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder;
|
||||
use Jikan\Helper\Constants;
|
||||
use Laravel\Scout\Builder as ScoutBuilder;
|
||||
|
||||
/**
|
||||
@ -60,4 +63,42 @@ final class DefaultAnimeRepository extends DatabaseRepository implements AnimeRe
|
||||
->where("rank", ">", 0)
|
||||
->orderBy("rank");
|
||||
}
|
||||
|
||||
public function getCurrentlyAiring(
|
||||
?AnimeScheduleFilterEnum $filter = null,
|
||||
bool $kids = false,
|
||||
bool $sfw = false): EloquentBuilder
|
||||
{
|
||||
/*
|
||||
* all have status as currently airing
|
||||
* all have premiered, but they're not necessarily the current season or year
|
||||
* all have aired date, but they're not necessarily the current date/season
|
||||
*/
|
||||
$queryable = $this->queryable(true)
|
||||
->orderBy("members")
|
||||
->where("type", AnimeTypeEnum::tv()->label)
|
||||
->where("status", AnimeStatusEnum::airing()->label);
|
||||
|
||||
if ($kids) {
|
||||
$queryable = $queryable->where("demographics.mal_id", Constants::GENRE_ANIME_KIDS);
|
||||
}
|
||||
else {
|
||||
$queryable = $queryable->where("demographics.mal_id", "!=", Constants::GENRE_ANIME_KIDS);
|
||||
}
|
||||
|
||||
if ($sfw) {
|
||||
$queryable = $queryable->where("demographics.mal_id", "!=", Constants::GENRE_ANIME_HENTAI);
|
||||
}
|
||||
|
||||
if (!is_null($filter)) {
|
||||
if ($filter->isWeekDay()) {
|
||||
$queryable = $queryable->where("broadcast", "like", "{$filter->label}%");
|
||||
}
|
||||
else {
|
||||
$queryable = $queryable->where("broadcast", $filter->label);
|
||||
}
|
||||
}
|
||||
|
||||
return $queryable;
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,9 @@ namespace App\Repositories;
|
||||
|
||||
use App\Contracts\MangaRepository;
|
||||
use App\Enums\MangaStatusEnum;
|
||||
use App\Enums\MangaTypeEnum;
|
||||
use App\Manga;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder;
|
||||
use Laravel\Scout\Builder as ScoutBuilder;
|
||||
|
||||
class DefaultMangaRepository extends DatabaseRepository implements MangaRepository
|
||||
@ -44,4 +45,9 @@ class DefaultMangaRepository extends DatabaseRepository implements MangaReposito
|
||||
->where("rank", ">", 0)
|
||||
->orderBy("rank");
|
||||
}
|
||||
|
||||
public function exceptItemsWithAdultRating(): EloquentBuilder|ScoutBuilder
|
||||
{
|
||||
return $this->queryable()->where("type", "!=", MangaTypeEnum::doujin()->label);
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,6 @@ use App\Contracts\Repository;
|
||||
use App\Http\HttpHelper;
|
||||
use App\Support\CachedData;
|
||||
use Illuminate\Contracts\Database\Query\Builder;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Jikan\MyAnimeList\MalClient;
|
||||
use MongoDB\BSON\UTCDateTime;
|
||||
@ -110,15 +107,6 @@ final class DefaultCachedScraperService implements CachedScraperService
|
||||
return CachedData::from($this->getByCacheKey($cacheKey));
|
||||
}
|
||||
|
||||
public function augmentResponse(JsonResponse|Response $response, string $cacheKey, CachedData $scraperResults): JsonResponse|Response
|
||||
{
|
||||
return $response
|
||||
->header("X-Request-Fingerprint", $cacheKey)
|
||||
->setTtl($this->cacheTtl())
|
||||
->setExpires(Carbon::createFromTimestamp($scraperResults->expiry()))
|
||||
->setLastModified(Carbon::createFromTimestamp($scraperResults->lastModified()));
|
||||
}
|
||||
|
||||
private function raiseNotFoundIfEmpty(CachedData $results)
|
||||
{
|
||||
if ($results->isEmpty()) {
|
||||
|
@ -73,11 +73,11 @@ final class CachedData
|
||||
|
||||
$result = $this->scraperResult->first();
|
||||
|
||||
if (is_array($result)) {
|
||||
if (is_array($result) && array_key_exists("modifiedAt", $result)) {
|
||||
return (int) $result["modifiedAt"]->toDateTime()->format("U");
|
||||
}
|
||||
|
||||
if (is_object($result)) {
|
||||
if (is_object($result) && property_exists($result, "modifiedAt")) {
|
||||
return $result->modifiedAt->toDateTime()->format("U");
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user