Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.40",
"phpstan/phpstan": "^1.10 || ^2.0",
"phpstan/phpstan": "^1.10 || ^2.2",
"phpunit/phpunit": "^10.5",
"symfony/var-dumper": "^6.4",
"vlucas/phpdotenv": "^5.6"
Expand Down
4 changes: 4 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ parameters:
- src
- tests
ignoreErrors:
# Lombok Getter/Setter and DevTools With assign via magic methods.
-
identifier: property.unusedType
path: src/*
12 changes: 5 additions & 7 deletions src/Client/SlidingWindowRateLimiter.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,11 @@ public function acquire(): void

$this->requests[] = $this->now();

$lastTimestamp = end($this->requests);
if ($lastTimestamp !== false) {
$elapsed = $now - $lastTimestamp;
if ($elapsed < $minInterval && $elapsed > 0.0) {
$sleep = $minInterval - $elapsed;
usleep((int) ($sleep * 1_000_000));
}
$lastTimestamp = $this->requests[array_key_last($this->requests)];
$elapsed = $now - $lastTimestamp;
if ($elapsed < $minInterval && $elapsed > 0.0) {
$sleep = $minInterval - $elapsed;
usleep((int) ($sleep * 1_000_000));
}
}

Expand Down
28 changes: 18 additions & 10 deletions src/Config/SdkConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,43 +193,51 @@ private static function envNullableString(string $key, ?string $default): ?strin
{
$value = $_ENV[$key] ?? $_SERVER[$key] ?? getenv($key);

if ($value === false || $value === '') {
if (!\is_string($value) || $value === '') {
return $default;
}

return (string) $value;
return $value;
}

private static function envInt(string $key, int $default): int
{
$value = $_ENV[$key] ?? $_SERVER[$key] ?? getenv($key);

if ($value === false || $value === '') {
return $default;
if (\is_int($value)) {
return $value;
}

if (\is_string($value) && $value !== '' && is_numeric($value)) {
return (int) $value;
}

return (int) $value;
return $default;
}

private static function envNullableInt(string $key, ?int $default): ?int
{
$value = $_ENV[$key] ?? $_SERVER[$key] ?? getenv($key);

if ($value === false || $value === '') {
return $default;
if (\is_int($value)) {
return $value;
}

if (\is_string($value) && $value !== '' && is_numeric($value)) {
return (int) $value;
}

return (int) $value;
return $default;
}

private static function envBool(string $key, bool $default): bool
{
$value = $_ENV[$key] ?? $_SERVER[$key] ?? getenv($key);

if ($value === false || $value === '') {
if (!\is_string($value) || $value === '') {
return $default;
}

return \in_array(strtolower((string) $value), ['1', 'true', 'yes', 'on'], true);
return \in_array(strtolower($value), ['1', 'true', 'yes', 'on'], true);
}
}
74 changes: 25 additions & 49 deletions src/DTO/AnimeDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Devcraft\Abstracts\AbstractWith;
use Devcraft\Attributes\With;
use Devcraft\Attributes\WithItem;
use DevCraftClub\Shikimori\Util\ArrayUtil;
use Lombok\Getter;
use Lombok\Setter;

Expand Down Expand Up @@ -119,43 +120,41 @@ public function __construct()
private array $studios = [];

/**
* @param array<string, mixed> $data
* @param array<array-key, mixed> $data
*/
public static function fromArray(array $data): self
{
$id = $data['id'] ?? 0;
$anime = (new self())
->withId(\is_int($id) || \is_string($id) ? $id : 0)
->withName(\is_string($data['name'] ?? null) ? (string) $data['name'] : '')
->withRussian(\is_string($data['russian'] ?? null) ? (string) $data['russian'] : null)
->withKind(\is_string($data['kind'] ?? null) ? (string) $data['kind'] : null)
->withStatus(\is_string($data['status'] ?? null) ? (string) $data['status'] : null)
->withScore(self::optionalFloat($data['score'] ?? null))
->withEpisodes(self::optionalInt($data['episodes'] ?? null))
->withEpisodesAired(self::optionalInt($data['episodesAired'] ?? null))
->withDescription(\is_string($data['description'] ?? null) ? (string) $data['description'] : null)
->withUrl(\is_string($data['url'] ?? null) ? (string) $data['url'] : null)
->withDuration(self::optionalInt($data['duration'] ?? null))
->withRating(\is_string($data['rating'] ?? null) ? (string) $data['rating'] : null)
->withFranchise(\is_string($data['franchise'] ?? null) ? (string) $data['franchise'] : null)
->withAiredOn(\is_string($data['airedOn'] ?? null) ? (string) $data['airedOn'] : null)
->withReleasedOn(\is_string($data['releasedOn'] ?? null) ? (string) $data['releasedOn'] : null)
->withPoster(PosterDTO::fromArray(\is_array($data['poster'] ?? null) ? $data['poster'] : null))
->withUpdatedAt(self::parseDateTime($data['updatedAt'] ?? null));

$genres = $data['genres'] ?? null;
if (\is_array($genres)) {
->withName(ArrayUtil::stringOrDefault($data, 'name', ''))
->withRussian(ArrayUtil::optionalString($data, 'russian'))
->withKind(ArrayUtil::optionalString($data, 'kind'))
->withStatus(ArrayUtil::optionalString($data, 'status'))
->withScore(ArrayUtil::optionalFloat($data, 'score'))
->withEpisodes(ArrayUtil::optionalInt($data, 'episodes'))
->withEpisodesAired(ArrayUtil::optionalInt($data, 'episodesAired'))
->withDescription(ArrayUtil::optionalString($data, 'description'))
->withUrl(ArrayUtil::optionalString($data, 'url'))
->withDuration(ArrayUtil::optionalInt($data, 'duration'))
->withRating(ArrayUtil::optionalString($data, 'rating'))
->withFranchise(ArrayUtil::optionalString($data, 'franchise'))
->withAiredOn(ArrayUtil::optionalString($data, 'airedOn'))
->withReleasedOn(ArrayUtil::optionalString($data, 'releasedOn'))
->withPoster(PosterDTO::fromArray(ArrayUtil::optionalArray($data, 'poster')))
->withUpdatedAt(ArrayUtil::optionalDateTime($data, 'updatedAt'));

$genres = ArrayUtil::optionalListOfMaps($data, 'genres');
if ($genres !== null) {
foreach ($genres as $genre) {
if (\is_array($genre)) {
$anime = $anime->withGenresItem(GenreDTO::fromArray($genre));
}
$anime = $anime->withGenresItem(GenreDTO::fromArray($genre));
}
}

$studios = $data['studios'] ?? null;
if (\is_array($studios)) {
$studios = ArrayUtil::optionalListOfMaps($data, 'studios');
if ($studios !== null) {
foreach ($studios as $studio) {
$studioDto = StudioDTO::fromArray(\is_array($studio) ? $studio : null);
$studioDto = StudioDTO::fromArray($studio);
if ($studioDto !== null) {
$anime = $anime->withStudiosItem($studioDto);
}
Expand Down Expand Up @@ -198,27 +197,4 @@ public function toArray(): array
),
];
}

private static function parseDateTime(mixed $value): ?DateTimeImmutable
{
if (!\is_string($value) || $value === '') {
return null;
}

try {
return new DateTimeImmutable($value);
} catch (\Throwable) {
return null;
}
}

private static function optionalInt(mixed $value): ?int
{
return \is_int($value) ? $value : null;
}

private static function optionalFloat(mixed $value): ?float
{
return \is_int($value) || \is_float($value) ? (float) $value : null;
}
}
2 changes: 1 addition & 1 deletion src/DTO/CharacterDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function __construct()
private ?DateTimeImmutable $updatedAt = null;

/**
* @param array<string, mixed> $data
* @param array<array-key, mixed> $data
*/
public static function fromArray(array $data): self
{
Expand Down
2 changes: 1 addition & 1 deletion src/DTO/ContestDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public function __construct()
private ?DateTimeImmutable $updatedAt = null;

/**
* @param array<string, mixed> $data
* @param array<array-key, mixed> $data
*/
public static function fromArray(array $data): self
{
Expand Down
2 changes: 1 addition & 1 deletion src/DTO/GenreDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public function __construct()
private ?string $kind = null;

/**
* @param array<string, mixed> $data
* @param array<array-key, mixed> $data
*/
public static function fromArray(array $data): self
{
Expand Down
8 changes: 3 additions & 5 deletions src/DTO/MangaDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ public function __construct()
private array $genres = [];

/**
* @param array<string, mixed> $data
* @param array<array-key, mixed> $data
*/
public static function fromArray(array $data): self
{
Expand All @@ -120,12 +120,10 @@ public static function fromArray(array $data): self
->withUpdatedAt(ArrayUtil::optionalDateTime($data, 'updatedAt'))
->withPoster(PosterDTO::fromArray(ArrayUtil::optionalArray($data, 'poster')));

$genres = ArrayUtil::optionalArray($data, 'genres');
$genres = ArrayUtil::optionalListOfMaps($data, 'genres');
if ($genres !== null) {
foreach ($genres as $genre) {
if (\is_array($genre)) {
$manga = $manga->withGenresItem(GenreDTO::fromArray($genre));
}
$manga = $manga->withGenresItem(GenreDTO::fromArray($genre));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/DTO/PersonDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function __construct()
private ?DateTimeImmutable $updatedAt = null;

/**
* @param array<string, mixed> $data
* @param array<array-key, mixed> $data
*/
public static function fromArray(array $data): self
{
Expand Down
2 changes: 1 addition & 1 deletion src/DTO/PosterDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function __construct()
private ?string $mainUrl = null;

/**
* @param array<string, mixed>|null $data
* @param array<array-key, mixed>|null $data
*/
public static function fromArray(?array $data): ?self
{
Expand Down
2 changes: 1 addition & 1 deletion src/DTO/StudioDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public function __construct()
private ?string $imageUrl = null;

/**
* @param array<string, mixed>|null $data
* @param array<array-key, mixed>|null $data
*/
public static function fromArray(?array $data): ?self
{
Expand Down
2 changes: 1 addition & 1 deletion src/DTO/UserDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public function __construct()
private ?DateTimeImmutable $createdAt = null;

/**
* @param array<string, mixed> $data
* @param array<array-key, mixed> $data
*/
public static function fromArray(array $data): self
{
Expand Down
9 changes: 5 additions & 4 deletions src/DTO/UserRateDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ public function __construct()
private ?AnimeDTO $target = null;

/**
* @param array<string, mixed> $data
* @param array<array-key, mixed> $data
*/
public static function fromArray(array $data): self
{
$id = $data['id'] ?? 0;
$target = $data['target'] ?? null;
$user = ArrayUtil::optionalArray($data, 'user');
$target = ArrayUtil::optionalArray($data, 'target');

return (new self())
->withId(\is_int($id) || \is_string($id) ? $id : 0)
Expand All @@ -94,8 +95,8 @@ public static function fromArray(array $data): self
->withRewatches(ArrayUtil::optionalInt($data, 'rewatches'))
->withCreatedAt(ArrayUtil::optionalDateTime($data, 'createdAt'))
->withUpdatedAt(ArrayUtil::optionalDateTime($data, 'updatedAt'))
->withUser(\is_array($data['user'] ?? null) ? UserDTO::fromArray($data['user']) : null)
->withTarget(\is_array($target) ? AnimeDTO::fromArray($target) : null);
->withUser($user !== null ? UserDTO::fromArray($user) : null)
->withTarget($target !== null ? AnimeDTO::fromArray($target) : null);
}

/**
Expand Down
7 changes: 4 additions & 3 deletions src/Entity/AnimeEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use DateTimeImmutable;
use DevCraftClub\Shikimori\DTO\AnimeDTO;
use DevCraftClub\Shikimori\Persistence\StorableEntity;
use DevCraftClub\Shikimori\Util\ArrayUtil;

#[Entity(table: 'shikimori_animes')]
class AnimeEntity implements StorableEntity
Expand Down Expand Up @@ -108,9 +109,9 @@ public function updateFromArray(array $data): void
$this->setAiredOn(\is_string($data['airedOn'] ?? null) ? (string) $data['airedOn'] : null);
$this->setReleasedOn(\is_string($data['releasedOn'] ?? null) ? (string) $data['releasedOn'] : null);
$this->setUpdatedAt(self::parseDateTime($data['updatedAt'] ?? null));
$this->setPoster(\is_array($data['poster'] ?? null) ? $data['poster'] : null);
$this->setGenres(\is_array($data['genres'] ?? null) ? $data['genres'] : null);
$this->setStudios(\is_array($data['studios'] ?? null) ? $data['studios'] : null);
$this->setPoster(ArrayUtil::optionalArray($data, 'poster'));
$this->setGenres(ArrayUtil::optionalListOfMaps($data, 'genres'));
$this->setStudios(ArrayUtil::optionalListOfMaps($data, 'studios'));
$this->markFetchedNow();
}

Expand Down
1 change: 0 additions & 1 deletion src/Persistence/CycleEntityStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public function __construct(

public function findById(string $entityClass, int|string $id): ?StorableEntity
{
/** @phpstan-ignore-next-line Cycle template resolution */
$repository = $this->orm->getRepository($entityClass);
$entity = $repository->findByPK($id);

Expand Down
Loading
Loading