diff --git a/composer.json b/composer.json index b69de464..319baa7d 100755 --- a/composer.json +++ b/composer.json @@ -36,6 +36,7 @@ "jakub-onderka/php-parallel-lint": "^1.0", "jikan-me/jikan-fixtures": "dev-master", "php-vcr/php-vcr": "^1.6", + "php-vcr/phpunit-testlistener-vcr": "^3.1", "phpro/grumphp": "^1.7.0", "phpunit/phpunit": "~9.0", "squizlabs/php_codesniffer": "^3.3" diff --git a/src/Helper/Constants.php b/src/Helper/Constants.php index 1da83e31..99271d18 100644 --- a/src/Helper/Constants.php +++ b/src/Helper/Constants.php @@ -35,12 +35,10 @@ class Constants public const TOP_TV = 'tv'; public const TOP_MOVIE = 'movie'; public const TOP_OVA = 'ova'; - public const TOP_ONA = 'ona'; public const TOP_SPECIAL = 'special'; public const TOP_ONA = 'ona'; public const TOP_MANGA = 'manga'; - public const TOP_LIGHTNOVELS = 'lightnovels'; public const TOP_NOVEL = 'novels'; public const TOP_ONE_SHOT = 'oneshots'; public const TOP_DOUJINSHI = 'doujin'; @@ -51,9 +49,12 @@ class Constants public const TOP_BY_POPULARITY = 'bypopularity'; public const TOP_BY_FAVORITES = 'favorite'; - public const TOP_REVIEW_ANIME = 'anime'; - public const TOP_REVIEW_MANGA = 'manga'; - public const TOP_REVIEW_BEST_VOTED = 'bestvoted'; + public const RECENT_REVIEW_ANIME = 'anime'; + public const RECENT_REVIEW_MANGA = 'manga'; + public const RECENT_REVIEW_BEST_VOTED = 'bestvoted'; + + public const RECENT_RECOMMENDATION_ANIME = 'anime'; + public const RECENT_RECOMMENDATION_MANGA = 'manga'; // v3 status const // remove old ones public const STATUS_ANIME_AIRING = 1; @@ -132,6 +133,11 @@ class Constants public const SEARCH_MANGA_ORDER_BY_TYPE = 8; // Default: Manhua, Manhwa, Doujinshi, One-shot, Novel, Manga public const SEARCH_MANGA_ORDER_BY_ID = 9; + public const SEARCH_USER_GENDER_ANY = -1; + public const SEARCH_USER_GENDER_MALE = 1; + public const SEARCH_USER_GENDER_FEMALE = 2; + public const SEARCH_USER_GENDER_NONBINARY = 3; + public const GENRE_ANIME_ACTION = 1; public const GENRE_ANIME_ADVENTURE = 2; public const GENRE_ANIME_CARS = 3; diff --git a/src/Helper/Parser.php b/src/Helper/Parser.php index 6cbf39ef..bdd2001c 100644 --- a/src/Helper/Parser.php +++ b/src/Helper/Parser.php @@ -51,6 +51,29 @@ public static function idFromUrl(string $url): int return (int)preg_replace('#https://myanimelist.net(/\w+/)(\d+).*#', '$2', $url); } + /** + * Extract club ID from MAL URl + * + * @param string $url + * @return int + */ + public static function clubIdFromUrl(string $url) : int + { + return (int) preg_replace('~.*\.php\?cid=([\d]+)$~', '$1', $url); + } + + /** + * Extract the last property id from a mal url (e.g episode ID) + * + * @param string $url + * + * @return int + */ + public static function suffixIdFromUrl(string $url): int + { + return (int) preg_replace('#https://myanimelist.net/.*/(\d+)#', '$1', $url); + } + /** * @param string $date * @@ -192,7 +215,7 @@ public static function textOrNull(Crawler $crawler): ?string public static function parseImageQuality(string $imageUrl) : string { // adding `v` prefix returns a very small thumbnail, as opposed to adding `l` - $imageUrl = str_replace(['v.jpg'], '.jpg', $imageUrl); + $imageUrl = str_replace(['v.jpg', 't.jpg', 'l.jpg'], '.jpg', $imageUrl); return preg_replace('~/r/\d+x\d+~', '', $imageUrl); } @@ -207,6 +230,10 @@ public static function parseImageThumbToHQ(string $imageUrl) : string return str_replace(['thumbs/', '_thumb'], '', $imageUrl); } + /** + * @param string $duration + * @return int|null + */ public static function parseDurationToSeconds(string $duration): ?int { preg_match('~([0-9]{2}):([0-9]{2}):([0-9]{2})~', $duration, $match); diff --git a/src/Jikan.php b/src/Jikan.php deleted file mode 100755 index db0e5c08..00000000 --- a/src/Jikan.php +++ /dev/null @@ -1,839 +0,0 @@ -myanimelist = new MalClient($guzzle); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Anime\Anime - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Anime(int $id): Model\Anime\Anime - { - return $this->myanimelist->getAnime( - new Request\Anime\AnimeRequest($id) - ); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Anime\AnimeCharactersAndStaff - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeCharactersAndStaff(int $id): Model\Anime\AnimeCharactersAndStaff - { - return $this->myanimelist->getAnimeCharactersAndStaff( - new Request\Anime\AnimeCharactersAndStaffRequest($id) - ); - } - - /** - * @param int $id - * @param int $page - * - * @return \Jikan\Model\Anime\Episodes - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeEpisodes(int $id, int $page = 1): Model\Anime\Episodes - { - return $this->myanimelist->getAnimeEpisodes( - new Request\Anime\AnimeEpisodesRequest($id, $page) - ); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Anime\AnimeVideos - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeVideos(int $id): Model\Anime\AnimeVideos - { - return $this->myanimelist->getAnimeVideos( - new Request\Anime\AnimeVideosRequest($id) - ); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Common\Picture[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimePictures(int $id): array - { - return $this->myanimelist->getAnimePictures( - new Request\Anime\AnimePicturesRequest($id) - ); - } - - - /** - * @param int $id - * - * @return Model\News\NewsListItem[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeNews(int $id): array - { - return $this->myanimelist->getNewsList( - new Request\Anime\AnimeNewsRequest($id) - ); - } - - /** - * @param int $id - * - * @return Model\Forum\ForumTopic[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeForum(int $id, ?string $topic = null): array - { - return $this->myanimelist->getAnimeForum( - new Request\Anime\AnimeForumRequest($id, $topic) - ); - } - - /** - * @param int $id - * - * @return Model\Anime\AnimeStats - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeStats(int $id): Model\Anime\AnimeStats - { - return $this->myanimelist->getAnimeStats( - new Request\Anime\AnimeStatsRequest($id) - ); - } - - /** - * @param int $id - * - * @return string|null - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeMoreInfo(int $id): ?string - { - return $this->myanimelist->getAnimeMoreInfo( - new Request\Anime\AnimeMoreInfoRequest($id) - ); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Manga\Manga - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Manga(int $id): Model\Manga\Manga - { - return $this->myanimelist->getManga( - new Request\Manga\MangaRequest($id) - ); - } - - /** - * @param int $id - * - * @return Model\Manga\CharacterListItem[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaCharacters(int $id): array - { - return $this->myanimelist->getMangaCharacters( - new Request\Manga\MangaCharactersRequest($id) - ); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Common\Picture[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaPictures(int $id): array - { - return $this->myanimelist->getMangaPictures( - new Request\Manga\MangaPicturesRequest($id) - ); - } - - /** - * @param int $id - * - * @return Model\News\NewsListItem[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaNews(int $id): array - { - return $this->myanimelist->getNewsList( - new Request\Manga\MangaNewsRequest($id) - ); - } - - /** - * @param int $id - * - * @return Model\Forum\ForumTopic[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaForum(int $id): array - { - return $this->myanimelist->getMangaForum( - new Request\Manga\MangaForumRequest($id) - ); - } - - /** - * @param int $id - * - * @return Model\Manga\MangaStats - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaStats(int $id): Model\Manga\MangaStats - { - return $this->myanimelist->getMangaStats( - new Request\Manga\MangaStatsRequest($id) - ); - } - - /** - * @param int $id - * - * @return string|null - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaMoreInfo(int $id): ?string - { - return $this->myanimelist->getMangaMoreInfo( - new Request\Manga\MangaMoreInfoRequest($id) - ); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Character\Character - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Character(int $id): Model\Character\Character - { - return $this->myanimelist->getCharacter( - new Request\Character\CharacterRequest($id) - ); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Common\Picture[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function CharacterPictures(int $id): array - { - return $this->myanimelist->getCharacterPictures( - new Request\Character\CharacterPicturesRequest($id) - ); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Person\Person - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Person(int $id): Model\Person\Person - { - return $this->myanimelist->getPerson( - new Request\Person\PersonRequest($id) - ); - } - - /** - * @param int $id - * - * @return \Jikan\Model\Common\Picture[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function PersonPictures(int $id): array - { - return $this->myanimelist->getPersonPictures( - new Request\Person\PersonPicturesRequest($id) - ); - } - - /** - * @param int|null $year - * @param string|null $season - * @return \Jikan\Model\Seasonal\Seasonal - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Seasonal(?int $year = null, ?string $season = null): Model\Seasonal\Seasonal - { - return $this->myanimelist->getSeasonal( - new Request\Seasonal\SeasonalRequest($year, $season) - ); - } - - /** - * - * @return array - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function SeasonList(): array - { - return $this->myanimelist->getSeasonList( - new Request\SeasonList\SeasonListRequest() - ); - } - - /** - * - * @return \Jikan\Model\Schedule\Schedule - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Schedule(): Model\Schedule\Schedule - { - return $this->myanimelist->getSchedule( - new Request\Schedule\ScheduleRequest() - ); - } - - /** - * @param int $id - * @param int $page - * - * @return \Jikan\Model\Producer\Producer - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Producer(int $id, int $page = 1): Model\Producer\Producer - { - return $this->myanimelist->getProducer( - new Request\Producer\ProducerRequest($id, $page) - ); - } - - /** - * @param int $id - * @param int $page - * - * @return \Jikan\Model\Magazine\Magazine - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Magazine(int $id, int $page = 1): Model\Magazine\Magazine - { - return $this->myanimelist->getMagazine( - new Request\Magazine\MagazineRequest($id, $page) - ); - } - - /** - * @param int $id - * @param int $page - * - * @return \Jikan\Model\Genre\AnimeGenre - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeGenre(int $id, int $page = 1): Model\Genre\AnimeGenre - { - return $this->myanimelist->getAnimeGenre( - new Request\Genre\AnimeGenreRequest($id, $page) - ); - } - - /** - * @param int $id - * @param int $page - * - * @return \Jikan\Model\Genre\MangaGenre - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaGenre(int $id, int $page = 1): Model\Genre\MangaGenre - { - return $this->myanimelist->getMangaGenre( - new Request\Genre\MangaGenreRequest($id, $page) - ); - } - - /** - * @param int $page - * @param string|null $type - * - * @return Model\Top\TopAnime[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function TopAnime(int $page = 1, ?string $type = null): array - { - return $this->myanimelist->getTopAnime( - new Request\Top\TopAnimeRequest($page, $type) - ); - } - - /** - * @param int $page - * @param string|null $type - * - * @return Model\Top\TopManga[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function TopManga(int $page = 1, ?string $type = null): array - { - return $this->myanimelist->getTopManga( - new Request\Top\TopMangaRequest($page, $type) - ); - } - - /** - * @param int $page - * - * @return Model\Top\TopCharacter[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function TopCharacters(int $page = 1): array - { - return $this->myanimelist->getTopCharacters( - new Request\Top\TopCharactersRequest($page) - ); - } - - /** - * @param int $page - * - * @return Model\Top\TopPerson[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function TopPeople(int $page = 1): array - { - return $this->myanimelist->getTopPeople( - new Request\Top\TopPeopleRequest($page) - ); - } - - /** - * @param string|null $query - * @param int $page - * @param null|Request\Search\AnimeSearchRequest $request - * - * @return Model\Search\AnimeSearch - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeSearch( - ?string $query, - int $page = 1, - ?Request\Search\AnimeSearchRequest $request = null - ): Model\Search\AnimeSearch { - return $this->myanimelist->getAnimeSearch( - null !== $request - ? $request - ->setQuery($query) - ->setPage($page) - : new Request\Search\AnimeSearchRequest($query, $page) - ); - } - - /** - * @param string|null $query - * @param int $page - * @param null|Request\Search\MangaSearchRequest $request - * - * @return Model\Search\MangaSearch - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaSearch( - ?string $query, - int $page = 1, - ?Request\Search\MangaSearchRequest $request = null - ): Model\Search\MangaSearch { - return $this->myanimelist->getMangaSearch( - null !== $request - ? $request - ->setQuery($query) - ->setPage($page) - : new Request\Search\MangaSearchRequest($query, $page) - ); - } - - /** - * @param string|null $query - * @param int $page - * @param null|Request\Search\CharacterSearchRequest $request - * - * @return Model\Search\CharacterSearch - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function CharacterSearch( - ?string $query, - int $page = 1, - ?Request\Search\CharacterSearchRequest $request = null - ): Model\Search\CharacterSearch { - return $this->myanimelist->getCharacterSearch( - null !== $request - ? $request - ->setQuery($query) - ->setPage($page) - : new Request\Search\CharacterSearchRequest($query, $page) - ); - } - - /** - * @param string|null $query - * @param int $page - * @param Request\Search\PersonSearchRequest|Request\Search\PersonSearchRequest|null $request - * - * @return Model\Search\PersonSearch - * @throws ParserException - */ - public function PersonSearch( - ?string $query, - int $page = 1, - ?Request\Search\PersonSearchRequest $request = null - ): Model\Search\PersonSearch { - return $this->myanimelist->getPersonSearch( - null !== $request - ? $request - ->setQuery($query) - ->setPage($page) - : new Request\Search\PersonSearchRequest($query, $page) - ); - } - - /** - * @param string $username - * - * @return \Jikan\Model\User\Profile - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function UserProfile(string $username): Model\User\Profile - { - return $this->myanimelist->getUserProfile( - new Request\User\UserProfileRequest($username) - ); - } - - /** - * @param string $username - * @param int $page - * - * @return Model\User\Friend[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function UserFriends(string $username, int $page = 1): array - { - return $this->myanimelist->getUserFriends( - new Request\User\UserFriendsRequest($username, $page) - ); - } - - /** - * @param string $username - * @param string|null $type - * - * @return array - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function UserHistory(string $username, ?string $type = null): array - { - return $this->myanimelist->getUserHistory( - new Request\User\UserHistoryRequest($username, $type) - ); - } - - /** - * @param string $username - * @param int $page - * @param int $status - * - * @return array - * @throws ParserException - */ - public function UserAnimeList(string $username, int $page = 1, int $status = 7): array - { - return $this->myanimelist->getUserAnimeList( - new Request\User\UserAnimeListRequest($username, $page, $status) - ); - } - - /** - * @param string $username - * @param int $page - * @param int $status - * - * @return array - * @throws ParserException - */ - public function UserMangaList(string $username, int $page = 1, int $status = 7): array - { - return $this->myanimelist->getUserMangaList( - new Request\User\UserMangaListRequest($username, $page, $status) - ); - } - - - /** - * @param int $id - * @param int $page - * - * @return array - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeRecentlyUpdatedByUsers(int $id, int $page = 1): array - { - return $this->myanimelist->getAnimeRecentlyUpdatedByUsers( - new Request\Anime\AnimeRecentlyUpdatedByUsersRequest($id, $page) - ); - } - - /** - * @param int $id - * @param int $page - * - * @return array - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaRecentlyUpdatedByUsers(int $id, int $page = 1): array - { - return $this->myanimelist->getMangaRecentlyUpdatedByUsers( - new Request\Manga\MangaRecentlyUpdatedByUsersRequest($id, $page) - ); - } - - /** - * @param int $id - * - * @return array - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeRecommendations(int $id): array - { - return $this->myanimelist->getAnimeRecommendations( - new Request\Anime\AnimeRecommendationsRequest($id) - ); - } - - /** - * @param int $id - * @return array - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaRecommendations(int $id): array - { - return $this->myanimelist->getMangaRecommendations( - new Request\Manga\MangaRecommendationsRequest($id) - ); - } - - /** - * @param int $id - * @param int $page - * - * @return array|Model\Club\UserProfile[] - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function ClubUsers(int $id, int $page = 1): array - { - return $this->myanimelist->getClubUsers( - new Request\Club\UserListRequest($id, $page) - ); - } - - /** - * @param int $id - * @param int $page - * @return array - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeReviews(int $id, int $page): array - { - return $this->myanimelist->getAnimeReviews( - new Request\Anime\AnimeReviewsRequest($id, $page) - ); - } - - /** - * @param int $id - * @param int $page - * @return array - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaReviews(int $id, int $page): array - { - return $this->myanimelist->getMangaReviews( - new Request\Manga\MangaReviewsRequest($id, $page) - ); - } - - /** - * @param int $id - * @return Model\Club\Club - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Club(int $id): Model\Club\Club - { - return $this->myanimelist->getClub( - new Request\Club\ClubRequest($id) - ); - } - - /** - * @param int $id - * @param int $episodeId - * @return Model\Anime\AnimeEpisode - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeEpisode(int $id, int $episodeId): Model\Anime\AnimeEpisode - { - return $this->myanimelist->getAnimeEpisode( - new Request\Anime\AnimeEpisodeRequest($id, $episodeId) - ); - } - - - /** - * @return Model\Producer\ProducerList - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Producers(): Model\Producer\ProducerList - { - return $this->myanimelist->getProducers( - new Request\Producer\ProducersRequest() - ); - } - - /** - * @return Model\Magazine\MagazineList - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function Magazines(): Model\Magazine\MagazineList - { - return $this->myanimelist->getMagazines( - new Request\Magazine\MagazinesRequest() - ); - } - - /** - * @return Model\Genre\AnimeGenreList - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function AnimeGenres(): Model\Genre\AnimeGenreList - { - return $this->myanimelist->getAnimeGenres( - new Request\Genre\AnimeGenresRequest() - ); - } - - /** - * @return Model\Genre\MangaGenreList - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function MangaGenres(): Model\Genre\MangaGenreList - { - return $this->myanimelist->getMangaGenres( - new Request\Genre\MangaGenresRequest() - ); - } - - /** - * @param int $page - * @param string|null $type - * - * @return array - * @throws Exception\BadResponseException - * @throws ParserException - */ - public function TopReviews(?string $type = Constants::TOP_REVIEW_BEST_VOTED, int $page = 1): array - { - return $this->myanimelist->getTopReviews( - new Request\Top\TopReviewsRequest($type, $page) - ); - } -} diff --git a/src/Model/Anime/AnimeEpisode.php b/src/Model/Anime/AnimeEpisode.php index 929ca80b..ed9a80ff 100644 --- a/src/Model/Anime/AnimeEpisode.php +++ b/src/Model/Anime/AnimeEpisode.php @@ -15,7 +15,7 @@ class AnimeEpisode /** * @var int */ - private $episodeId; + private $malId; /** * @var string @@ -72,7 +72,7 @@ public static function fromParser(AnimeEpisodeParser $parser): self { $instance = new self(); - $instance->episodeId = $parser->getEpisodeId(); + $instance->malId = $parser->getEpisodeId(); $instance->url = $parser->getEpisodeUrl(); $instance->filler = $parser->getFiller(); $instance->recap = $parser->getRecap(); @@ -93,9 +93,9 @@ public static function fromParser(AnimeEpisodeParser $parser): self /** * @return int */ - public function getEpisodeId(): int + public function getMalId(): int { - return $this->episodeId; + return $this->malId; } /** diff --git a/src/Model/Anime/StreamEpisodeListItem.php b/src/Model/Anime/StreamEpisodeListItem.php index 8eda1071..85bb654e 100644 --- a/src/Model/Anime/StreamEpisodeListItem.php +++ b/src/Model/Anime/StreamEpisodeListItem.php @@ -12,6 +12,11 @@ */ class StreamEpisodeListItem { + /** + * @var int + */ + public $malId; + /** * @var string */ @@ -41,6 +46,7 @@ class StreamEpisodeListItem public static function fromParser(StreamEpisodeListItemParser $parser): self { $instance = new self(); + $instance->malId = $parser->getMalId(); $instance->title = $parser->getTitle(); $instance->episode = $parser->getEpisode(); $instance->url = $parser->getUrl(); @@ -49,6 +55,14 @@ public static function fromParser(StreamEpisodeListItemParser $parser): self return $instance; } + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + /** * @return string */ diff --git a/src/Model/Common/ClubMeta.php b/src/Model/Common/ClubMeta.php new file mode 100644 index 00000000..0555aacd --- /dev/null +++ b/src/Model/Common/ClubMeta.php @@ -0,0 +1,67 @@ +malId = $malId; + $instance->name = $name; + $instance->url = $url; + + return $instance; + } + + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } +} diff --git a/src/Model/Common/Collection/Pagination.php b/src/Model/Common/Collection/Pagination.php new file mode 100644 index 00000000..68ff5c00 --- /dev/null +++ b/src/Model/Common/Collection/Pagination.php @@ -0,0 +1,24 @@ +results; + } + + /** + * @param array $results + * @return Results + */ + public function setResults(array $results): Results + { + $this->results = $results; + return $this; + } +} diff --git a/src/Model/Common/Picture.php b/src/Model/Common/Picture.php index 59c1ff88..e5193166 100644 --- a/src/Model/Common/Picture.php +++ b/src/Model/Common/Picture.php @@ -14,13 +14,12 @@ class Picture /** * @var string */ - private $large; + private $imageUrl; /** * @var string */ - private $small; - + private $largeImageUrl; /** * @param PictureParser $parser @@ -31,8 +30,8 @@ class Picture public static function fromParser(PictureParser $parser): Picture { $instance = new self(); - $instance->large = $parser->getLarge(); - $instance->small = $parser->getSmall(); + $instance->largeImageUrl = $parser->getLarge(); + $instance->imageUrl = $parser->getSmall(); return $instance; } @@ -40,16 +39,16 @@ public static function fromParser(PictureParser $parser): Picture /** * @return string */ - public function getLarge(): string + public function getImageUrl(): string { - return $this->large; + return $this->imageUrl; } /** * @return string */ - public function getSmall(): string + public function getLargeImageUrl(): string { - return $this->small; + return $this->largeImageUrl; } } diff --git a/src/Model/Common/User.php b/src/Model/Common/User.php new file mode 100644 index 00000000..0b2cfbea --- /dev/null +++ b/src/Model/Common/User.php @@ -0,0 +1,38 @@ +url; + } + + /** + * @return string + */ + public function getUsername(): string + { + return $this->username; + } +} diff --git a/src/Model/Common/YoutubeMeta.php b/src/Model/Common/YoutubeMeta.php new file mode 100644 index 00000000..5403812b --- /dev/null +++ b/src/Model/Common/YoutubeMeta.php @@ -0,0 +1,82 @@ +embedUrl = $embedUrl; + $instance->youtubeId = Media::youtubeIdFromUrl($embedUrl); + $instance->url = Media::generateYoutubeUrlFromId($instance->youtubeId); + $instance->images = Media::generateYoutubeImageResource($instance->youtubeId); + + return $instance; + } + + /** + * @return string|null + */ + public function getYoutubeId(): ?string + { + return $this->youtubeId; + } + + /** + * @return string|null + */ + public function getUrl(): ?string + { + return $this->url; + } + + /** + * @return string|null + */ + public function getEmbedUrl(): ?string + { + return $this->embedUrl; + } + + /** + * @return YoutubeImageResource + */ + public function getImages(): YoutubeImageResource + { + return $this->images; + } +} diff --git a/src/Model/Forum/ForumPost.php b/src/Model/Forum/ForumPost.php index cfaa9144..fc429d51 100644 --- a/src/Model/Forum/ForumPost.php +++ b/src/Model/Forum/ForumPost.php @@ -18,7 +18,7 @@ class ForumPost /** * @var string */ - private $authorName; + private $authorUsername; /** * @var string @@ -28,22 +28,22 @@ class ForumPost /** * @var \DateTimeImmutable|null */ - private $datePosted; + private $date; /** * ForumPost constructor. * * @param string $url - * @param string $authorName + * @param string $authorUsername * @param string $authorUrl * @param \DateTimeImmutable|null $relativeDate */ - public function __construct(string $url, string $authorName, string $authorUrl, ?\DateTimeImmutable $relativeDate) + public function __construct(string $url, string $authorUsername, string $authorUrl, ?\DateTimeImmutable $relativeDate) { $this->url = $url; - $this->authorName = $authorName; + $this->authorUsername = $authorUsername; $this->authorUrl = $authorUrl; - $this->datePosted = $relativeDate; + $this->date = $relativeDate; } /** @@ -57,9 +57,9 @@ public function getUrl(): string /** * @return string */ - public function getAuthorName(): string + public function getAuthorUsername(): string { - return $this->authorName; + return $this->authorUsername; } /** @@ -73,8 +73,8 @@ public function getAuthorUrl(): string /** * @return \DateTimeImmutable|null */ - public function getDatePosted(): ?\DateTimeImmutable + public function getDate(): ?\DateTimeImmutable { - return $this->datePosted; + return $this->date; } } diff --git a/src/Model/Forum/ForumTopic.php b/src/Model/Forum/ForumTopic.php index 8e34a341..d30e1657 100644 --- a/src/Model/Forum/ForumTopic.php +++ b/src/Model/Forum/ForumTopic.php @@ -14,7 +14,7 @@ class ForumTopic /** * @var int */ - private $topicId; + private $malId; /** * @var string @@ -29,12 +29,12 @@ class ForumTopic /** * @var \DateTimeImmutable */ - private $datePosted; + private $date; /** * @var string */ - private $authorName; + private $authorUsername; /** * @var string @@ -44,12 +44,12 @@ class ForumTopic /** * @var int */ - private $replies = 0; + private $comments = 0; /** * @var ForumPost */ - private $lastPost; + private $lastComment; /** * @param ForumTopicParser $parser @@ -60,32 +60,24 @@ class ForumTopic public static function fromParser(ForumTopicParser $parser): self { $instance = new self(); - $instance->topicId = $parser->getTopicId(); + $instance->malId = $parser->getTopicId(); $instance->url = $parser->getUrl(); $instance->title = $parser->getTitle(); - $instance->datePosted = $parser->getPostDate(); - $instance->replies = $parser->getReplies(); - $instance->authorName = $parser->getAuthorName(); + $instance->date = $parser->getPostDate(); + $instance->comments = $parser->getReplies(); + $instance->authorUsername = $parser->getAuthorName(); $instance->authorUrl = $parser->getAuthorUrl(); - $instance->lastPost = $parser->getLastPost(); + $instance->lastComment = $parser->getLastPost(); return $instance; } - /** - * @return string - */ - public function __toString() - { - return $this->title; - } - /** * @return int */ - public function getTopicId(): int + public function getMalId(): int { - return $this->topicId; + return $this->malId; } /** @@ -107,17 +99,17 @@ public function getTitle(): string /** * @return \DateTimeImmutable */ - public function getDatePosted(): \DateTimeImmutable + public function getDate(): \DateTimeImmutable { - return $this->datePosted; + return $this->date; } /** * @return string */ - public function getAuthorName(): string + public function getAuthorUsername(): string { - return $this->authorName; + return $this->authorUsername; } /** @@ -131,16 +123,16 @@ public function getAuthorUrl(): string /** * @return int */ - public function getReplies(): int + public function getComments(): int { - return $this->replies; + return $this->comments; } /** * @return ForumPost */ - public function getLastPost(): ForumPost + public function getLastComment(): ForumPost { - return $this->lastPost; + return $this->lastComment; } } diff --git a/src/Model/Genre/AnimeGenre.php b/src/Model/Genre/AnimeGenre.php index 2665b962..dde57c0c 100644 --- a/src/Model/Genre/AnimeGenre.php +++ b/src/Model/Genre/AnimeGenre.php @@ -3,6 +3,8 @@ namespace Jikan\Model\Genre; use Jikan\Model\Common\AnimeCard; +use Jikan\Model\Common\Collection\Pagination; +use Jikan\Model\Common\Collection\Results; use Jikan\Model\Common\MalUrl; use Jikan\Parser\Genre\AnimeGenreParser; @@ -11,24 +13,38 @@ * * @package Jikan\Model */ -class AnimeGenre +class AnimeGenre extends Results implements Pagination { + /** + * @var int + */ + private $malId; + + /** + * @var string + */ + private $url; /** - * @var \Jikan\Model\Common\MalUrl + * @var string */ - public $malUrl; + private $name; /** * @var int */ - public $itemCount; + public $count; + + /** + * @var bool + */ + private $hasNextPage = false; /** - * @var array|AnimeCard[] + * @var int */ - public $anime = []; + private $lastVisiblePage = 1; /** * @param AnimeGenreParser $parser @@ -40,37 +56,70 @@ class AnimeGenre public static function fromParser(AnimeGenreParser $parser): self { $instance = new self(); - $instance->itemCount = $parser->getCount(); - $instance->anime = $parser->getGenreAnime(); - $instance->malUrl = new MalUrl( - $parser->getName(), - $parser->getUrl() - ); + $instance->count = $parser->getCount(); + $instance->results = $parser->getResults(); + $instance->name = $parser->getName(); + $instance->malId = $parser->getMalId(); + $instance->url = $parser->getUrl(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); return $instance; } /** - * @return \Jikan\Model\Common\MalUrl + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return int + */ + public function getCount(): int + { + return $this->count; + } + + /** + * @return bool */ - public function getMalUrl(): MalUrl + public function hasNextPage(): bool { - return $this->malUrl; + return $this->hasNextPage; } /** * @return int */ - public function getItemCount(): int + public function getLastVisiblePage(): int { - return $this->itemCount; + return $this->lastVisiblePage; } /** - * @return array|AnimeCard[] + * @return array */ - public function getAnime(): array + public function getResults(): array { - return $this->anime; + return $this->results; } } diff --git a/src/Model/Genre/AnimeGenreListItem.php b/src/Model/Genre/AnimeGenreListItem.php index 6df09d9c..9f12968a 100644 --- a/src/Model/Genre/AnimeGenreListItem.php +++ b/src/Model/Genre/AnimeGenreListItem.php @@ -12,6 +12,10 @@ */ class AnimeGenreListItem { + /** + * @var int + */ + private $malId; /** * @var string @@ -37,6 +41,7 @@ public static function fromParser(AnimeGenreListItemParser $parser): self { $instance = new self(); + $instance->malId = $parser->getMalId(); $instance->name = $parser->getName(); $instance->url = $parser->getUrl(); $instance->count = $parser->getCount(); @@ -44,6 +49,14 @@ public static function fromParser(AnimeGenreListItemParser $parser): self return $instance; } + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + /** * @return string */ diff --git a/src/Model/Genre/MangaGenre.php b/src/Model/Genre/MangaGenre.php index 7d4e242e..0d39a17f 100644 --- a/src/Model/Genre/MangaGenre.php +++ b/src/Model/Genre/MangaGenre.php @@ -2,32 +2,46 @@ namespace Jikan\Model\Genre; -use Jikan\Model\Common\MangaCard; +use Jikan\Model\Common\Collection\Pagination; +use Jikan\Model\Common\Collection\Results; use Jikan\Parser\Genre\MangaGenreParser; -use Jikan\Model\Common\MalUrl; /** * Class MangaGenre * * @package Jikan\Model */ -class MangaGenre +class MangaGenre extends Results implements Pagination { + /** + * @var int + */ + private $malId; + + /** + * @var string + */ + private $url; /** - * @var \Jikan\Model\Common\MalUrl + * @var string */ - public $malUrl; + private $name; /** * @var int */ - public $itemCount; + public $count; + + /** + * @var bool + */ + private $hasNextPage = false; /** - * @var array|MangaCard[] + * @var int */ - public $manga = []; + private $lastVisiblePage = 1; /** * @param MangaGenreParser $parser @@ -39,39 +53,71 @@ class MangaGenre public static function fromParser(MangaGenreParser $parser): self { $instance = new self(); - $instance->itemCount = $parser->getCount(); - $instance->manga = $parser->getGenreManga(); - $instance->malUrl = new MalUrl( - $parser->getName(), - $parser->getUrl() - ); + + $instance->count = $parser->getCount(); + $instance->results = $parser->getResults(); + $instance->name = $parser->getName(); + $instance->malId = $parser->getMalId(); + $instance->url = $parser->getUrl(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); return $instance; } /** - * @return \Jikan\Model\Common\MalUrl + * @return int */ - public function getMalUrl(): MalUrl + public function getMalId(): int { - return $this->malUrl; + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; } /** * @return int */ - public function getItemCount(): int + public function getCount(): int { - return $this->itemCount; + return $this->count; } /** - * @return array|MangaCard[] + * @return bool */ - public function getManga(): array + public function hasNextPage(): bool { - return $this->manga; + return $this->hasNextPage; } + /** + * @return int + */ + public function getLastVisiblePage(): int + { + return $this->lastVisiblePage; + } + /** + * @return array + */ + public function getResults(): array + { + return $this->results; + } } diff --git a/src/Model/Genre/MangaGenreList.php b/src/Model/Genre/MangaGenreList.php index 302d998f..c669b156 100644 --- a/src/Model/Genre/MangaGenreList.php +++ b/src/Model/Genre/MangaGenreList.php @@ -84,30 +84,4 @@ public function getGenres() { return $this->genres; } - - /** - * @return array|MangaGenreListItem[] - */ - public function getExplicitGenres(): array - { - return $this->explicitGenres; - } - - /** - * @return array|MangaGenreListItem[] - */ - public function getThemes(): array - { - return $this->themes; - } - - /** - * @return array|MangaGenreListItem[] - */ - public function getDemographics(): array - { - return $this->demographics; - } - - } diff --git a/src/Model/Genre/MangaGenreListItem.php b/src/Model/Genre/MangaGenreListItem.php index e9c41c05..fa7faec6 100644 --- a/src/Model/Genre/MangaGenreListItem.php +++ b/src/Model/Genre/MangaGenreListItem.php @@ -13,6 +13,11 @@ class MangaGenreListItem { + /** + * @var int + */ + private $malId; + /** * @var string */ @@ -37,6 +42,7 @@ public static function fromParser(MangaGenreListItemParser $parser): self { $instance = new self(); + $instance->malId = $parser->getMalId(); $instance->name = $parser->getName(); $instance->url = $parser->getUrl(); $instance->count = $parser->getCount(); @@ -44,6 +50,14 @@ public static function fromParser(MangaGenreListItemParser $parser): self return $instance; } + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + /** * @return string */ diff --git a/src/Model/Magazine/Magazine.php b/src/Model/Magazine/Magazine.php index 358b09c0..853d159e 100644 --- a/src/Model/Magazine/Magazine.php +++ b/src/Model/Magazine/Magazine.php @@ -2,6 +2,8 @@ namespace Jikan\Model\Magazine; +use Jikan\Model\Common\Collection\Pagination; +use Jikan\Model\Common\Collection\Results; use Jikan\Model\Common\MalUrl; use Jikan\Parser\Magazine\MagazineParser; @@ -10,18 +12,33 @@ * * @package Jikan\Model */ -class Magazine +class Magazine extends Results implements Pagination { /** - * @var \Jikan\Model\Common\MalUrl + * @var int */ - public $malUrl; + private $malId; /** - * @var array|MagazineManga[] + * @var string */ - public $manga = []; + private $url; + + /** + * @var string + */ + private $name; + + /** + * @var bool + */ + private $hasNextPage = false; + + /** + * @var int + */ + private $lastVisiblePage = 1; /** * @param MagazineParser $parser @@ -33,25 +50,62 @@ class Magazine public static function fromParser(MagazineParser $parser): self { $instance = new self(); - $instance->malUrl = $parser->getUrl(); - $instance->manga = $parser->getMagazineManga(); + + $instance->malId = $parser->getUrl()->getMalId(); + $instance->url = $parser->getUrl()->getUrl(); + $instance->name = $parser->getUrl()->getName(); + $instance->results = $parser->getResults(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); return $instance; } /** - * @return \Jikan\Model\Common\MalUrl + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return bool + */ + public function hasNextPage(): bool + { + return $this->hasNextPage; + } + + /** + * @return int */ - public function getMalUrl(): MalUrl + public function getLastVisiblePage(): int { - return $this->malUrl; + return $this->lastVisiblePage; } /** - * @return array|MagazineManga[] + * @return array */ - public function getManga(): array + public function getResults(): array { - return $this->manga; + return $this->results; } } diff --git a/src/Model/Magazine/MagazineListItem.php b/src/Model/Magazine/MagazineListItem.php index 05db306b..eae607b6 100644 --- a/src/Model/Magazine/MagazineListItem.php +++ b/src/Model/Magazine/MagazineListItem.php @@ -13,6 +13,10 @@ */ class MagazineListItem { + /** + * @var int + */ + private $malId; /** * @var string @@ -39,6 +43,7 @@ class MagazineListItem public static function fromParser(MagazineListItemParser $parser): self { $instance = new self(); + $instance->malId = $parser->getMalId(); $instance->name = $parser->getName(); $instance->url = $parser->getUrl(); $instance->count = $parser->getCount(); @@ -46,6 +51,14 @@ public static function fromParser(MagazineListItemParser $parser): self return $instance; } + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + /** * @return string */ diff --git a/src/Model/News/NewsList.php b/src/Model/News/NewsList.php new file mode 100644 index 00000000..caabf289 --- /dev/null +++ b/src/Model/News/NewsList.php @@ -0,0 +1,73 @@ +results = $parser->getResults(); + $instance->hasNextPage = $parser->getHasNextPage(); + + return $instance; + } + + public static function mock() : self + { + return new self(); + } + + /** + * @return bool + */ + public function hasNextPage(): bool + { + return $this->hasNextPage; + } + + /** + * @return int + */ + public function getLastVisiblePage(): int + { + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; + } +} diff --git a/src/Model/News/NewsListItem.php b/src/Model/News/NewsListItem.php index fdeece48..bb41f537 100644 --- a/src/Model/News/NewsListItem.php +++ b/src/Model/News/NewsListItem.php @@ -12,6 +12,11 @@ */ class NewsListItem { + /** + * @var int|null + */ + private $malId; + /** * @var string */ @@ -30,7 +35,7 @@ class NewsListItem /** * @var string */ - private $authorName; + private $authorUsername; /** * @var string @@ -55,7 +60,7 @@ class NewsListItem /** * @var string */ - private $intro; + private $excerpt; /** * @param NewsListItemParser $parser @@ -66,19 +71,28 @@ class NewsListItem public static function fromParser(NewsListItemParser $parser): self { $instance = new self(); + $instance->malId = $parser->getMalId(); $instance->url = $parser->getUrl(); $instance->title = $parser->getTitle(); $instance->date = $parser->getDate(); - $instance->authorName = $parser->getAuthor()->getName(); + $instance->authorUsername = $parser->getAuthor()->getName(); $instance->authorUrl = $parser->getAuthor()->getUrl(); $instance->forumUrl = $parser->getDiscussionLink(); $instance->images = WrapImageResource::factory($parser->getImage()); $instance->comments = $parser->getComments(); - $instance->intro = $parser->getIntro(); + $instance->excerpt = $parser->getIntro(); return $instance; } + /** + * @return int|null + */ + public function getMalId(): ?int + { + return $this->malId; + } + /** * @return string */ @@ -106,9 +120,9 @@ public function getDate(): \DateTimeImmutable /** * @return string */ - public function getAuthorName(): string + public function getAuthorUsername(): string { - return $this->authorName; + return $this->authorUsername; } /** @@ -146,8 +160,8 @@ public function getComments(): int /** * @return string */ - public function getIntro(): string + public function getExcerpt(): string { - return $this->intro; + return $this->excerpt; } } diff --git a/src/Model/Producer/Producer.php b/src/Model/Producer/Producer.php index d11af479..ddebb10b 100644 --- a/src/Model/Producer/Producer.php +++ b/src/Model/Producer/Producer.php @@ -2,7 +2,10 @@ namespace Jikan\Model\Producer; +use Jikan\Model\Common\Collection\Pagination; +use Jikan\Model\Common\Collection\Results; use Jikan\Model\Common\MalUrl; +use Jikan\Model\Top\TopPeople; use Jikan\Parser\Producer\ProducerParser; /** @@ -10,18 +13,33 @@ * * @package Jikan\Model */ -class Producer +class Producer extends Results implements Pagination { /** - * @var MalUrl + * @var int */ - public $malUrl; + private $malId; /** - * @var array|ProducerAnime[] + * @var string */ - public $anime = []; + private $url; + + /** + * @var string + */ + private $name; + + /** + * @var bool + */ + private $hasNextPage = false; + + /** + * @var int + */ + private $lastVisiblePage = 1; /** * @param ProducerParser $parser @@ -33,25 +51,62 @@ class Producer public static function fromParser(ProducerParser $parser): self { $instance = new self(); - $instance->malUrl = $parser->getUrl(); - $instance->anime = $parser->getProducerAnime(); + + $instance->malId = $parser->getUrl()->getMalId(); + $instance->url = $parser->getUrl()->getUrl(); + $instance->name = $parser->getUrl()->getName(); + $instance->results = $parser->getResults(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); return $instance; } /** - * @return MalUrl + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return bool + */ + public function hasNextPage(): bool + { + return $this->hasNextPage; + } + + /** + * @return int */ - public function getMalUrl(): MalUrl + public function getLastVisiblePage(): int { - return $this->malUrl; + return $this->lastVisiblePage; } /** - * @return array|ProducerAnime[] + * @return array */ - public function getAnime(): array + public function getResults(): array { - return $this->anime; + return $this->results; } } diff --git a/src/Model/Producer/ProducerListItem.php b/src/Model/Producer/ProducerListItem.php index 214c4583..b83a5e0b 100644 --- a/src/Model/Producer/ProducerListItem.php +++ b/src/Model/Producer/ProducerListItem.php @@ -13,6 +13,10 @@ */ class ProducerListItem { + /** + * @var int + */ + private $malId; /** * @var string @@ -39,6 +43,7 @@ class ProducerListItem public static function fromParser(ProducerListItemParser $parser): self { $instance = new self(); + $instance->malId = $parser->getMalId(); $instance->name = $parser->getName(); $instance->url = $parser->getUrl(); $instance->count = $parser->getCount(); @@ -46,6 +51,14 @@ public static function fromParser(ProducerListItemParser $parser): self return $instance; } + /** + * @return int + */ + public function getMalId(): int + { + return $this->malId; + } + /** * @return string */ diff --git a/src/Model/Recommendations/Recommender.php b/src/Model/Recommendations/Recommender.php new file mode 100644 index 00000000..cd4b5e65 --- /dev/null +++ b/src/Model/Recommendations/Recommender.php @@ -0,0 +1,23 @@ +url = $url; + $instance->username = $username; + + return $instance; + } +} diff --git a/src/Model/Reviews/Reviewer.php b/src/Model/Reviews/Reviewer.php index 8131fbc2..f67a1fe0 100644 --- a/src/Model/Reviews/Reviewer.php +++ b/src/Model/Reviews/Reviewer.php @@ -24,7 +24,7 @@ public static function fromParser(ReviewerParser $parser): self { $instance = new self(); - $instance->url= $parser->getUrl(); + $instance->url = $parser->getUrl(); $instance->images = UserImageResource::factory($parser->getImageUrl()); $instance->username = $parser->getUsername(); diff --git a/src/Model/Search/AnimeSearch.php b/src/Model/Search/AnimeSearch.php index 2917c491..f10870dd 100644 --- a/src/Model/Search/AnimeSearch.php +++ b/src/Model/Search/AnimeSearch.php @@ -2,6 +2,8 @@ namespace Jikan\Model\Search; +use Jikan\Model\Common\Collection\Pagination; +use Jikan\Model\Common\Collection\Results; use Jikan\Parser; /** @@ -9,19 +11,18 @@ * * @package Jikan\Model\Search\Search */ -class AnimeSearch +class AnimeSearch extends Results implements Pagination { /** - * @var AnimeSearchListItem[] + * @var bool */ - private $results; + private $hasNextPage = false; /** * @var int */ - private $lastPage; - + private $lastVisiblePage = 1; /** * @param Parser\Search\AnimeSearchParser $parser @@ -36,24 +37,38 @@ public static function fromParser(Parser\Search\AnimeSearchParser $parser): self $instance = new self(); $instance->results = $parser->getResults(); - $instance->lastPage = $parser->getLastPage(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); return $instance; } + public static function mock() : self + { + return new self(); + } + /** - * @return AnimeSearchListItem[] + * @return bool */ - public function getResults(): array + public function hasNextPage(): bool { - return $this->results; + return $this->hasNextPage; } /** * @return int */ - public function getLastPage(): int + public function getLastVisiblePage(): int { - return $this->lastPage; + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; } } diff --git a/src/Model/Search/CharacterSearch.php b/src/Model/Search/CharacterSearch.php index 63d27ec2..09017c4c 100644 --- a/src/Model/Search/CharacterSearch.php +++ b/src/Model/Search/CharacterSearch.php @@ -2,6 +2,8 @@ namespace Jikan\Model\Search; +use Jikan\Model\Common\Collection\Pagination; +use Jikan\Model\Common\Collection\Results; use Jikan\Parser; /** @@ -9,24 +11,24 @@ * * @package Jikan\Model\Search\Search */ -class CharacterSearch +class CharacterSearch extends Results implements Pagination { /** - * @var CharacterSearchListItem[] + * @var bool */ - private $results; + private $hasNextPage = false; /** * @var int */ - private $lastPage; - + private $lastVisiblePage = 1; /** * @param Parser\Search\CharacterSearchParser $parser * * @return CharacterSearch + * @throws \Exception * @throws \RuntimeException * @throws \InvalidArgumentException */ @@ -35,24 +37,38 @@ public static function fromParser(Parser\Search\CharacterSearchParser $parser): $instance = new self(); $instance->results = $parser->getResults(); - $instance->lastPage = $parser->getLastPage(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); return $instance; } + public static function mock() : self + { + return new self(); + } + /** - * @return CharacterSearchListItem[] + * @return bool */ - public function getResults(): array + public function hasNextPage(): bool { - return $this->results; + return $this->hasNextPage; } /** * @return int */ - public function getLastPage(): int + public function getLastVisiblePage(): int { - return $this->lastPage; + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; } } diff --git a/src/Model/Search/PersonSearch.php b/src/Model/Search/PersonSearch.php index 624ac3d4..8a67f112 100644 --- a/src/Model/Search/PersonSearch.php +++ b/src/Model/Search/PersonSearch.php @@ -2,6 +2,8 @@ namespace Jikan\Model\Search; +use Jikan\Model\Common\Collection\Pagination; +use Jikan\Model\Common\Collection\Results; use Jikan\Parser; /** @@ -9,19 +11,18 @@ * * @package Jikan\Model\Search\Search */ -class PersonSearch +class PersonSearch extends Results implements Pagination { /** - * @var PersonSearchListItem[] + * @var bool */ - private $results = []; + private $hasNextPage = false; /** * @var int */ - private $lastPage = 1; - + private $lastVisiblePage = 1; /** * @param Parser\Search\PersonSearchParser $parser @@ -36,24 +37,38 @@ public static function fromParser(Parser\Search\PersonSearchParser $parser): sel $instance = new self(); $instance->results = $parser->getResults(); - $instance->lastPage = $parser->getLastPage(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); return $instance; } + public static function mock() : self + { + return new self(); + } + /** - * @return PersonSearchListItem[] + * @return bool */ - public function getResults(): array + public function hasNextPage(): bool { - return $this->results; + return $this->hasNextPage; } /** * @return int */ - public function getLastPage(): int + public function getLastVisiblePage(): int { - return $this->lastPage; + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; } } diff --git a/src/Model/Search/UserSearch.php b/src/Model/Search/UserSearch.php new file mode 100644 index 00000000..8eb1dee1 --- /dev/null +++ b/src/Model/Search/UserSearch.php @@ -0,0 +1,74 @@ +results = $parser->getResults(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); + + return $instance; + } + + public static function mock() : self + { + return new self(); + } + + /** + * @return bool + */ + public function hasNextPage(): bool + { + return $this->hasNextPage; + } + + /** + * @return int + */ + public function getLastVisiblePage(): int + { + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; + } +} diff --git a/src/Model/Seasonal/Seasonal.php b/src/Model/Seasonal/Seasonal.php index cf428fef..e0b492a6 100755 --- a/src/Model/Seasonal/Seasonal.php +++ b/src/Model/Seasonal/Seasonal.php @@ -67,5 +67,4 @@ public function getAnime() { return $this->anime; } - } diff --git a/src/Model/Top/TopAnime.php b/src/Model/Top/TopAnime.php index b5700f71..1156dc47 100755 --- a/src/Model/Top/TopAnime.php +++ b/src/Model/Top/TopAnime.php @@ -2,190 +2,73 @@ namespace Jikan\Model\Top; -use Jikan\Parser\Top\TopListItemParser; +use Jikan\Model\Common\Collection\Pagination; +use Jikan\Model\Common\Collection\Results; +use Jikan\Parser; /** * Class TopAnime * - * @package Jikan\Model + * @package Jikan\Model\Search\Search */ -class TopAnime +class TopAnime extends Results implements Pagination { - /** - * @var int - */ - private $malId; - - /** - * @var int - */ - private $rank; - - /** - * @var string - */ - private $title; - - /** - * @var string - */ - private $url; - - /** - * @var string - */ - private $imageUrl; - - /** - * @var string - */ - private $type; /** - * @var int - */ - private $episodes; - - /** - * @var string|null - */ - private $startDate; - - /** - * @var string|null + * @var bool */ - private $endDate; + private $hasNextPage = false; /** * @var int */ - private $members; - - /** - * @var float - */ - private $score; + private $lastVisiblePage = 1; /** - * Create an instance from an AnimeParser parser + * @param Parser\Top\TopAnimeParser $parser * - * @param TopListItemParser $parser - * - * @return self + * @return TopAnime + * @throws \Exception * @throws \RuntimeException * @throws \InvalidArgumentException */ - public static function fromParser(TopListItemParser $parser): self + public static function fromParser(Parser\Top\TopAnimeParser $parser): self { $instance = new self(); - $instance->rank = $parser->getRank(); - $instance->malId = $parser->getMalUrl()->getMalId(); - $instance->title = $parser->getMalUrl()->getTitle(); - $instance->url = $parser->getMalUrl()->getUrl(); - $instance->type = $parser->getType(); - $instance->episodes = $parser->getEpisodes(); - $instance->startDate = $parser->getStartDate(); - $instance->endDate = $parser->getEndDate(); - $instance->members = $parser->getMembers(); - $instance->score = $parser->getScore(); - $instance->imageUrl = $parser->getImage(); - return $instance; - } + $instance->results = $parser->getResults(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); - /** - * @return string - */ - public function __toString(): string - { - return $this->getTitle(); - } - - /** - * @return int - */ - public function getRank(): int - { - return $this->rank; - } - - /** - * @return int - */ - public function getMalId(): int - { - return $this->malId; - } - - /** - * @return string - */ - public function getTitle(): string - { - return $this->title; - } - - /** - * @return string - */ - public function getUrl(): string - { - return $this->url; - } - - /** - * @return string - */ - public function getType(): string - { - return $this->type; - } - - /** - * @return int|null - */ - public function getEpisodes(): ?int - { - return $this->episodes; + return $instance; } - /** - * @return string|null - */ - public function getStartDate(): ?string + public static function mock() : self { - return $this->startDate; + return new self(); } /** - * @return string|null + * @return bool */ - public function getEndDate(): ?string + public function hasNextPage(): bool { - return $this->endDate; + return $this->hasNextPage; } /** * @return int */ - public function getMembers(): int - { - return $this->members; - } - - /** - * @return float - */ - public function getScore(): float + public function getLastVisiblePage(): int { - return $this->score; + return $this->lastVisiblePage; } /** - * @return string + * @return array */ - public function getImageUrl(): string + public function getResults(): array { - return $this->imageUrl; + return $this->results; } } diff --git a/src/Model/Top/TopCharacter.php b/src/Model/Top/TopCharacterListItem.php old mode 100755 new mode 100644 similarity index 98% rename from src/Model/Top/TopCharacter.php rename to src/Model/Top/TopCharacterListItem.php index 94b1b2f7..a5527537 --- a/src/Model/Top/TopCharacter.php +++ b/src/Model/Top/TopCharacterListItem.php @@ -7,11 +7,11 @@ use Jikan\Parser\Top\TopListItemParser; /** - * Class TopCharacter + * Class TopCharacterListItem * * @package Jikan\Model */ -class TopCharacter +class TopCharacterListItem { /** * @var int diff --git a/src/Model/Top/TopCharacters.php b/src/Model/Top/TopCharacters.php new file mode 100644 index 00000000..32c81a33 --- /dev/null +++ b/src/Model/Top/TopCharacters.php @@ -0,0 +1,74 @@ +results = $parser->getResults(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); + + return $instance; + } + + /** + * @return TopCharacters + */ + public static function mock() : self + { + return new self(); + } + + /** + * @return bool + */ + public function hasNextPage(): bool + { + return $this->hasNextPage; + } + + /** + * @return int + */ + public function getLastVisiblePage(): int + { + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; + } +} diff --git a/src/Model/Top/TopManga.php b/src/Model/Top/TopManga.php index 1d0505e7..d297f656 100755 --- a/src/Model/Top/TopManga.php +++ b/src/Model/Top/TopManga.php @@ -2,190 +2,73 @@ namespace Jikan\Model\Top; -use Jikan\Parser\Top\TopListItemParser; +use Jikan\Model\Common\Collection\Pagination; +use Jikan\Model\Common\Collection\Results; +use Jikan\Parser; /** - * Class TopManga + * Class AnimeSearch * - * @package Jikan\Model + * @package Jikan\Model\Search\Search */ -class TopManga +class TopManga extends Results implements Pagination { - /** - * @var int - */ - private $malId; - - /** - * @var int - */ - private $rank; - - /** - * @var string - */ - private $title; - - /** - * @var string - */ - private $url; - - /** - * @var string - */ - private $type; - - /** - * @var int|null - */ - private $volumes; /** - * @var string|null + * @var bool */ - private $startDate; - - /** - * @var string|null - */ - private $endDate; + private $hasNextPage = false; /** * @var int */ - private $members; - - /** - * @var float - */ - private $score; - - /** - * @var string - */ - private $imageUrl; + private $lastVisiblePage = 1; /** - * Create an instance from an AnimeParser parser + * @param Parser\Search\AnimeSearchParser $parser * - * @param TopListItemParser $parser - * - * @return self + * @return TopManga + * @throws \Exception * @throws \RuntimeException * @throws \InvalidArgumentException */ - public static function fromParser(TopListItemParser $parser): self + public static function fromParser(Parser\Top\TopMangaParser $parser): self { $instance = new self(); - $instance->rank = $parser->getRank(); - $instance->malId = $parser->getMalUrl()->getMalId(); - $instance->title = $parser->getMalUrl()->getTitle(); - $instance->url = $parser->getMalUrl()->getUrl(); - $instance->type = $parser->getType(); - $instance->volumes = $parser->getVolumes(); - $instance->startDate = $parser->getStartDate(); - $instance->endDate = $parser->getEndDate(); - $instance->members = $parser->getMembers(); - $instance->score = $parser->getScore(); - $instance->imageUrl = $parser->getImage(); - - return $instance; - } - - /** - * @return string - */ - public function __toString(): string - { - return $this->getTitle(); - } - /** - * @return int - */ - public function getRank(): int - { - return $this->rank; - } + $instance->results = $parser->getResults(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); - /** - * @return int - */ - public function getMalId(): int - { - return $this->malId; - } - - /** - * @return string - */ - public function getTitle(): string - { - return $this->title; - } - - /** - * @return string - */ - public function getUrl(): string - { - return $this->url; - } - - /** - * @return string - */ - public function getType(): string - { - return $this->type; - } - - /** - * @return int|null - */ - public function getVolumes(): ?int - { - return $this->volumes; + return $instance; } - /** - * @return string|null - */ - public function getStartDate(): ?string + public static function mock() : self { - return $this->startDate; + return new self(); } /** - * @return string|null + * @return bool */ - public function getEndDate(): ?string + public function hasNextPage(): bool { - return $this->endDate; + return $this->hasNextPage; } /** * @return int */ - public function getMembers(): int - { - return $this->members; - } - - /** - * @return float - */ - public function getScore(): float + public function getLastVisiblePage(): int { - return $this->score; + return $this->lastVisiblePage; } /** - * @return string + * @return array */ - public function getImageUrl(): string + public function getResults(): array { - return $this->imageUrl; + return $this->results; } } diff --git a/src/Model/Top/TopPeople.php b/src/Model/Top/TopPeople.php new file mode 100644 index 00000000..f68b041e --- /dev/null +++ b/src/Model/Top/TopPeople.php @@ -0,0 +1,74 @@ +results = $parser->getResults(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastPage(); + + return $instance; + } + + public static function mock() : self + { + return new self(); + } + + /** + * @return bool + */ + public function hasNextPage(): bool + { + return $this->hasNextPage; + } + + /** + * @return int + */ + public function getLastVisiblePage(): int + { + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; + } +} diff --git a/src/Model/Top/TopPerson.php b/src/Model/Top/TopPersonListItem.php old mode 100755 new mode 100644 similarity index 98% rename from src/Model/Top/TopPerson.php rename to src/Model/Top/TopPersonListItem.php index 3138f6c1..9eb71bfe --- a/src/Model/Top/TopPerson.php +++ b/src/Model/Top/TopPersonListItem.php @@ -6,11 +6,11 @@ use Jikan\Parser\Top\TopListItemParser; /** - * Class TopPerson + * Class TopPersonListItem * * @package Jikan\Model */ -class TopPerson +class TopPersonListItem { /** * @var int diff --git a/src/Model/Watch/EpisodeListItem.php b/src/Model/Watch/EpisodeListItem.php index e2891ba4..ba8e3df4 100644 --- a/src/Model/Watch/EpisodeListItem.php +++ b/src/Model/Watch/EpisodeListItem.php @@ -3,7 +3,7 @@ namespace Jikan\Model\Watch; use Jikan\Model\Common\AnimeMeta; -use Jikan\Model\Resource\CommonImageResource\CommonImageResource; +use Jikan\Parser\ParserInterface; use Jikan\Parser\Watch\EpisodeListItemParser; /** @@ -35,7 +35,7 @@ class EpisodeListItem * @return EpisodeListItem * @throws \Exception */ - public static function fromParser(EpisodeListItemParser $parser): EpisodeListItem + public static function fromParser(ParserInterface $parser): EpisodeListItem { $instance = new self(); $instance->entry = $parser->getAnimeMeta(); diff --git a/src/Model/Watch/Episodes.php b/src/Model/Watch/Episodes.php new file mode 100644 index 00000000..27432ed1 --- /dev/null +++ b/src/Model/Watch/Episodes.php @@ -0,0 +1,63 @@ +results = $parser->getResults(); + + return $instance; + } + + /** + * @return bool + */ + public function hasNextPage(): bool + { + return $this->hasNextPage; + } + + /** + * @return int + */ + public function getLastVisiblePage(): int + { + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; + } +} diff --git a/src/Model/Watch/PromotionalVideos.php b/src/Model/Watch/PromotionalVideos.php new file mode 100644 index 00000000..5ef6662f --- /dev/null +++ b/src/Model/Watch/PromotionalVideos.php @@ -0,0 +1,65 @@ +results = $parser->getResults(); + $instance->hasNextPage = $parser->getHasNextPage(); + $instance->lastVisiblePage = $parser->getLastVisiblePage(); + + return $instance; + } + + /** + * @return bool + */ + public function hasNextPage(): bool + { + return $this->hasNextPage; + } + + /** + * @return int|null + */ + public function getLastVisiblePage(): ?int + { + return $this->lastVisiblePage; + } + + /** + * @return array + */ + public function getResults(): array + { + return $this->results; + } +} diff --git a/src/Parser/Anime/StreamEpisodeListItemParser.php b/src/Parser/Anime/StreamEpisodeListItemParser.php index 73afb25e..9e89eb89 100644 --- a/src/Parser/Anime/StreamEpisodeListItemParser.php +++ b/src/Parser/Anime/StreamEpisodeListItemParser.php @@ -29,6 +29,20 @@ public function __construct(Crawler $crawler) $this->crawler = $crawler; } + /** + * @return int|null + */ + public function getMalId() : ?int + { + preg_match('~([\d]+)$~', $this->getUrl(), $matches); + + if (!empty($matches)) { + return $matches[1]; + } + + return null; + } + /** * @return StreamEpisodeListItem * @throws \InvalidArgumentException diff --git a/src/Parser/Genre/AnimeGenreListItemParser.php b/src/Parser/Genre/AnimeGenreListItemParser.php index 95cc6a38..49750fed 100644 --- a/src/Parser/Genre/AnimeGenreListItemParser.php +++ b/src/Parser/Genre/AnimeGenreListItemParser.php @@ -39,6 +39,19 @@ public function getModel(): Model\Genre\AnimeGenreListItem return Model\Genre\AnimeGenreListItem::fromParser($this); } + /** + * @return int|null + */ + public function getMalId() : ?int + { + preg_match('~(\d+)/.*$~', $this->getUrl(), $matches); + + if (!empty($matches)) { + return $matches[1]; + } + + return null; + } /** * @return string diff --git a/src/Parser/Genre/AnimeGenreParser.php b/src/Parser/Genre/AnimeGenreParser.php index 91b142fb..a7c55289 100644 --- a/src/Parser/Genre/AnimeGenreParser.php +++ b/src/Parser/Genre/AnimeGenreParser.php @@ -46,7 +46,7 @@ public function getModel(): Model\Genre\AnimeGenre * @throws \InvalidArgumentException * @throws \RuntimeException */ - public function getGenreAnime(): array + public function getResults(): array { return $this->crawler ->filter('div.seasonal-anime') @@ -84,9 +84,11 @@ public function getUrl(): string */ public function getName(): string { - return JString::cleanse( + $name = JString::cleanse( Parser::removeChildNodes($this->crawler->filterXPath('//span[@class=\'di-ib mt4\']'))->text() ); + + return preg_replace('~(.*?)\sAnime~', '$1', $name); } /** @@ -108,4 +110,54 @@ public function getCount(): int $count->text() ); } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[5]/div/a[contains(@class, "link")]'); + + if (!$pages->count()) { + return 1; + } + + $pages = $pages + ->nextAll() + ->last(); + + if (!$pages->count()) { + return 1; + } + + preg_match('~\?page=(\d+)$~', $pages->attr('href'), $page); + + return $page[1]; + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[5]/div/a[contains(@class, "link")]'); + + if (!$pages->count()) { + return false; + } + + $pages = $pages + ->nextAll() + ->last() + ->filterXPath('//a[not(contains(@class, "current"))]'); + + if (!$pages->count()) { + return false; + } + + return true; + } } diff --git a/src/Parser/Genre/MangaGenreListItemParser.php b/src/Parser/Genre/MangaGenreListItemParser.php index 496b3644..7e5d52b1 100644 --- a/src/Parser/Genre/MangaGenreListItemParser.php +++ b/src/Parser/Genre/MangaGenreListItemParser.php @@ -39,6 +39,19 @@ public function getModel(): Model\Genre\MangaGenreListItem return Model\Genre\MangaGenreListItem::fromParser($this); } + /** + * @return int|null + */ + public function getMalId() : ?int + { + preg_match('~(\d+)/.*$~', $this->getUrl(), $matches); + + if (!empty($matches)) { + return $matches[1]; + } + + return null; + } /** * @return string diff --git a/src/Parser/Genre/MangaGenreParser.php b/src/Parser/Genre/MangaGenreParser.php index b3a3a054..ff5fa265 100644 --- a/src/Parser/Genre/MangaGenreParser.php +++ b/src/Parser/Genre/MangaGenreParser.php @@ -46,7 +46,7 @@ public function getModel(): Model\Genre\MangaGenre * @throws \InvalidArgumentException * @throws \RuntimeException */ - public function getGenreManga(): array + public function getResults(): array { return $this->crawler ->filter('div.seasonal-anime') @@ -108,4 +108,54 @@ public function getCount(): int $count->text() ); } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[5]/div/a[contains(@class, "link")]'); + + if (!$pages->count()) { + return 1; + } + + $pages = $pages + ->nextAll() + ->last(); + + if (!$pages->count()) { + return 1; + } + + preg_match('~\?page=(\d+)$~', $pages->attr('href'), $page); + + return $page[1]; + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[5]/div/a[contains(@class, "link")]'); + + if (!$pages->count()) { + return false; + } + + $pages = $pages + ->nextAll() + ->last() + ->filterXPath('//a[not(contains(@class, "current"))]'); + + if (!$pages->count()) { + return false; + } + + return true; + } } diff --git a/src/Parser/Magazine/MagazineListItemParser.php b/src/Parser/Magazine/MagazineListItemParser.php index 37c9f31f..e2cb8155 100644 --- a/src/Parser/Magazine/MagazineListItemParser.php +++ b/src/Parser/Magazine/MagazineListItemParser.php @@ -39,6 +39,20 @@ public function getModel(): Model\Magazine\MagazineListItem return Model\Magazine\MagazineListItem::fromParser($this); } + /** + * @return int|null + */ + public function getMalId() : ?int + { + preg_match('~(\d+)/.*$~', $this->getUrl(), $matches); + + if (!empty($matches)) { + return $matches[1]; + } + + return null; + } + /** * @return string * @throws \InvalidArgumentException diff --git a/src/Parser/Magazine/MagazineParser.php b/src/Parser/Magazine/MagazineParser.php index bad51e04..8bde58ea 100644 --- a/src/Parser/Magazine/MagazineParser.php +++ b/src/Parser/Magazine/MagazineParser.php @@ -46,7 +46,7 @@ public function getModel(): Model\Magazine\Magazine * @throws \InvalidArgumentException * @throws \RuntimeException */ - public function getMagazineManga(): array + public function getResults(): array { return $this->crawler ->filter('div.seasonal-anime') @@ -71,4 +71,54 @@ public function getUrl(): Model\Common\MalUrl $this->crawler->filterXPath('//meta[@property="og:url"]')->attr('content') ); } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[5]/div/a[contains(@class, "link")]'); + + if (!$pages->count()) { + return 1; + } + + $pages = $pages + ->nextAll() + ->last(); + + if (!$pages->count()) { + return 1; + } + + preg_match('~\?page=(\d+)$~', $pages->attr('href'), $page); + + return $page[1]; + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[5]/div/a[contains(@class, "link")]'); + + if (!$pages->count()) { + return false; + } + + $pages = $pages + ->nextAll() + ->last() + ->filterXPath('//a[not(contains(@class, "current"))]'); + + if (!$pages->count()) { + return false; + } + + return true; + } } diff --git a/src/Parser/Manga/CharactersParser.php b/src/Parser/Manga/CharactersParser.php index 0ab56527..10ea8183 100644 --- a/src/Parser/Manga/CharactersParser.php +++ b/src/Parser/Manga/CharactersParser.php @@ -41,10 +41,5 @@ function (Crawler $crawler) { return CharacterListItem::fromParser(new CharacterListItemParser($crawler)); } ); -// ->each( -// function (Crawler $crawler) { -// return CharacterListItem::fromParser(new CharacterListItemParser($crawler)); -// } -// ); } } diff --git a/src/Parser/News/NewsListItemParser.php b/src/Parser/News/NewsListItemParser.php index 86d34749..13375950 100644 --- a/src/Parser/News/NewsListItemParser.php +++ b/src/Parser/News/NewsListItemParser.php @@ -52,6 +52,20 @@ public function getTitle(): string return $this->crawler->filterXPath('//p/a/strong')->text(); } + /** + * @return int|null + */ + public function getMalId() : ?int + { + preg_match('~([\d]+)$~', $this->getUrl(), $matches); + + if (!empty($matches)) { + return $matches[1]; + } + + return null; + } + /** * @return string * @throws \InvalidArgumentException diff --git a/src/Parser/News/NewsListParser.php b/src/Parser/News/NewsListParser.php index caec27b4..9a36386f 100644 --- a/src/Parser/News/NewsListParser.php +++ b/src/Parser/News/NewsListParser.php @@ -2,7 +2,9 @@ namespace Jikan\Parser\News; +use Jikan\Model\News\NewsList; use Jikan\Model\News\NewsListItem; +use Jikan\Model\Search\AnimeSearch; use Jikan\Parser\ParserInterface; use Symfony\Component\DomCrawler\Crawler; @@ -28,12 +30,23 @@ public function __construct(Crawler $crawler) $this->crawler = $crawler; } + /** + * @return NewsList + * @throws \Exception + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): NewsList + { + return NewsList::fromParser($this); + } + /** * @return NewsListItem[] * @throws \RuntimeException * @throws \InvalidArgumentException */ - public function getModel(): array + public function getResults(): array { return $this->crawler ->filterXPath('//div[contains(@class,"js-scrollfix-bottom-rel")]/div[@class="clearfix"]') @@ -43,4 +56,19 @@ function (Crawler $crawler) { } ); } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/table/tr/td[2]/div[1]/a[contains(text(), "More News")]'); + + if ($pages->count()) { + return true; + } + + return false; + } } diff --git a/src/Parser/Person/VoiceActingRoleParser.php b/src/Parser/Person/VoiceActingRoleParser.php index 408c8d41..978b4a20 100644 --- a/src/Parser/Person/VoiceActingRoleParser.php +++ b/src/Parser/Person/VoiceActingRoleParser.php @@ -48,7 +48,6 @@ public function getModel(): Model\Person\VoiceActingRole */ public function getRole(): ?string { - $role = $this->crawler ->filterXPath('//td[3]/div[2]'); diff --git a/src/Parser/Producer/ProducerListItemParser.php b/src/Parser/Producer/ProducerListItemParser.php index 80fb1713..bebcabf3 100644 --- a/src/Parser/Producer/ProducerListItemParser.php +++ b/src/Parser/Producer/ProducerListItemParser.php @@ -42,6 +42,20 @@ public function getModel(): Model\Producer\ProducerListItem return Model\Producer\ProducerListItem::fromParser($this); } + /** + * @return int|null + */ + public function getMalId() : ?int + { + preg_match('~(\d+)/.*$~', $this->getUrl(), $matches); + + if (!empty($matches)) { + return $matches[1]; + } + + return null; + } + /** * @return string * @throws \InvalidArgumentException diff --git a/src/Parser/Producer/ProducerParser.php b/src/Parser/Producer/ProducerParser.php index 481974bd..46c7b926 100644 --- a/src/Parser/Producer/ProducerParser.php +++ b/src/Parser/Producer/ProducerParser.php @@ -46,7 +46,7 @@ public function getModel(): Model\Producer\Producer * @throws \InvalidArgumentException * @throws \RuntimeException */ - public function getProducerAnime(): array + public function getResults(): array { return $this->crawler ->filter('div.seasonal-anime') @@ -71,4 +71,54 @@ public function getUrl(): Model\Common\MalUrl $this->crawler->filterXPath('//meta[@property="og:url"]')->attr('content') ); } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[5]/div/a[contains(@class, "link")]'); + + if (!$pages->count()) { + return 1; + } + + $pages = $pages + ->nextAll() + ->last(); + + if (!$pages->count()) { + return 1; + } + + preg_match('~\?page=(\d+)$~', $pages->attr('href'), $page); + + return $page[1]; + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[5]/div/a[contains(@class, "link")]'); + + if (!$pages->count()) { + return false; + } + + $pages = $pages + ->nextAll() + ->last() + ->filterXPath('//a[not(contains(@class, "current"))]'); + + if (!$pages->count()) { + return false; + } + + return true; + } } diff --git a/src/Parser/Top/AnimeReviewParser.php b/src/Parser/Reviews/AnimeReviewParser.php similarity index 99% rename from src/Parser/Top/AnimeReviewParser.php rename to src/Parser/Reviews/AnimeReviewParser.php index c9cce376..fa68042c 100644 --- a/src/Parser/Top/AnimeReviewParser.php +++ b/src/Parser/Reviews/AnimeReviewParser.php @@ -5,7 +5,6 @@ use Jikan\Helper\JString; use Jikan\Helper\Parser; use Jikan\Model\Anime\AnimeReview; -use Jikan\Model\Anime\AnimeReviewer; use Jikan\Model\Anime\AnimeReviewScores; use Jikan\Model\Common\AnimeMeta; use Jikan\Model\Reviews\Reviewer; diff --git a/src/Parser/Top/AnimeReviewScoresParser.php b/src/Parser/Reviews/AnimeReviewScoresParser.php similarity index 100% rename from src/Parser/Top/AnimeReviewScoresParser.php rename to src/Parser/Reviews/AnimeReviewScoresParser.php diff --git a/src/Parser/Top/MangaReviewParser.php b/src/Parser/Reviews/MangaReviewParser.php similarity index 94% rename from src/Parser/Top/MangaReviewParser.php rename to src/Parser/Reviews/MangaReviewParser.php index 9c69358c..1aea2660 100644 --- a/src/Parser/Top/MangaReviewParser.php +++ b/src/Parser/Reviews/MangaReviewParser.php @@ -2,12 +2,11 @@ namespace Jikan\Parser\Reviews; +use Jikan\Exception\ParserException; use Jikan\Helper\JString; use Jikan\Helper\Parser; -use Jikan\Model\Common\AnimeMeta; use Jikan\Model\Common\MangaMeta; use Jikan\Model\Manga\MangaReview; -use Jikan\Model\Manga\MangaReviewer; use Jikan\Model\Manga\MangaReviewScores; use Jikan\Model\Reviews\Reviewer; use Jikan\Parser\Manga\MangaReviewScoresParser; @@ -22,9 +21,9 @@ class MangaReviewParser implements ParserInterface { /** - * @var Crawler + * @var \Symfony\Component\DomCrawler\Crawler */ - private $crawler; + private Crawler $crawler; /** * MangaReviewParser constructor. @@ -37,7 +36,7 @@ public function __construct(Crawler $crawler) } /** - * @return MangaReview + * @return \Jikan\Model\Manga\MangaReview * @throws \Exception * @throws \RuntimeException */ @@ -46,6 +45,9 @@ public function getModel(): MangaReview return MangaReview::fromParser($this); } + /** + * @throws \Jikan\Exception\ParserException + */ public function getManga() : MangaMeta { return new MangaMeta( @@ -192,6 +194,7 @@ public function getReviewedTitle(): string /** * @return string * @throws \InvalidArgumentException + * @throws \Jikan\Exception\ParserException */ public function getReviewedImageUrl(): string { @@ -210,6 +213,8 @@ public function getReviewedImageUrl(): string if ($node->count()) { return Parser::parseImageQuality($node->attr('data-src')); } + + throw new ParserException("Couldn't find the URL of reviewed image."); } /** diff --git a/src/Parser/Top/TopReviewsParser.php b/src/Parser/Reviews/RecentReviewsParser.php similarity index 52% rename from src/Parser/Top/TopReviewsParser.php rename to src/Parser/Reviews/RecentReviewsParser.php index 5d808ffc..d3fab705 100644 --- a/src/Parser/Top/TopReviewsParser.php +++ b/src/Parser/Reviews/RecentReviewsParser.php @@ -42,28 +42,32 @@ public function getModel(): RecentReviews /** * @return array * @throws \RuntimeException - * @throws \InvalidArgumentException + * @throws \InvalidArgumentException|\Exception */ public function getRecentReviews(): array { - return $this->crawler - ->filterXPath('//*[@id="content"]/div[@class="borderDark"]') - ->each( - function (Crawler $crawler) { - // If requested by $type `Constants::TOP_REVIEWS_BEST_VOTED`; both types can be returned - // So we check types here to allow the ability to parse and return both + return array_filter( + $this->crawler + ->filterXPath('//*[@id="content"]/div[@class="borderDark"]') + ->each( + function (Crawler $crawler) { + // If requested by $type `Constants::TOP_REVIEWS_BEST_VOTED`; both types can be returned + // So we check types here to allow the ability to parse and return both - // Anime Review - if ($crawler->filterXPath('//div[1]/div[1]/div[2]/small')->text() === '(Anime)') { - return RecentAnimeReview::fromParser(new AnimeReviewParser($crawler)); - } + // Anime Review + if ($crawler->filterXPath('//div[1]/div[1]/div[2]/small')->text() === '(Anime)') { + return RecentAnimeReview::fromParser(new AnimeReviewParser($crawler)); + } + + // Manga Review + if ($crawler->filterXPath('//div[1]/div[1]/div[2]/small')->text() === '(Manga)') { + return RecentMangaReview::fromParser(new MangaReviewParser($crawler)); + } - // Manga Review - if ($crawler->filterXPath('//div[1]/div[1]/div[2]/small')->text() === '(Manga)') { - return RecentMangaReview::fromParser(new MangaReviewParser($crawler)); + return null; } - } - ); + ) + ); } /** diff --git a/src/Parser/Top/ReviewerParser.php b/src/Parser/Reviews/ReviewerParser.php similarity index 94% rename from src/Parser/Top/ReviewerParser.php rename to src/Parser/Reviews/ReviewerParser.php index 7b67ec36..f7895222 100644 --- a/src/Parser/Top/ReviewerParser.php +++ b/src/Parser/Reviews/ReviewerParser.php @@ -2,12 +2,11 @@ namespace Jikan\Parser\Reviews; -use Jikan\Helper\JString; +use Jikan\Exception\ParserException; use Jikan\Helper\Parser; use Jikan\Model\Anime\AnimeReviewScores; use Jikan\Model\Manga\MangaReviewScores; use Jikan\Model\Reviews\Reviewer; -use Jikan\Parser\Anime\AnimeReviewScoresParser; use Jikan\Parser\Manga\MangaReviewScoresParser; use Jikan\Parser\ParserInterface; use Symfony\Component\DomCrawler\Crawler; @@ -42,6 +41,7 @@ public function getModel() /** * @return string * @throws \InvalidArgumentException + * @throws \Jikan\Exception\ParserException */ public function getUrl(): string { @@ -56,6 +56,8 @@ public function getUrl(): string if ($node->count()) { return $node->attr('href'); } + + throw new ParserException("Couldn't find any URL on review pages."); } /** diff --git a/src/Parser/Search/AnimeSearchListItemParser.php b/src/Parser/Search/AnimeSearchListItemParser.php index a147a9df..f8bc4075 100644 --- a/src/Parser/Search/AnimeSearchListItemParser.php +++ b/src/Parser/Search/AnimeSearchListItemParser.php @@ -46,7 +46,7 @@ public function getModel(): AnimeSearchListItem */ public function getUrl(): string { - return $this->crawler->filterXPath('//td[2]/div/a')->attr('href'); + return $this->crawler->filterXPath('//td[2]/a')->attr('href'); } /** @@ -55,7 +55,7 @@ public function getUrl(): string */ public function getTitle(): string { - return $this->crawler->filterXPath('//td[2]/div/a/strong')->text(); + return $this->crawler->filterXPath('//td[2]/a/strong')->text(); } /** diff --git a/src/Parser/Search/AnimeSearchParser.php b/src/Parser/Search/AnimeSearchParser.php index c1ed5625..78ceb57a 100644 --- a/src/Parser/Search/AnimeSearchParser.php +++ b/src/Parser/Search/AnimeSearchParser.php @@ -69,12 +69,33 @@ function (Crawler $c) { public function getLastPage(): int { $pages = $this->crawler - ->filterXPath('//div[contains(@class, "normal_header")]/div/div/span/a'); + ->filterXPath('//div[contains(@class, "normal_header")]/div/div/span'); if (!$pages->count()) { return 1; } - return (int)$pages->last()->text(); + $pages = explode(' ', $pages->text()); + + return (int) str_replace(['[', ']'], '', end($pages)); + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//div[contains(@class, "normal_header")]/div/div/span'); + + if (!$pages->count()) { + return false; + } + + if (preg_match('~\[\d+]\s(\d+)~', $pages->text())) { + return true; + } + + return false; } } diff --git a/src/Parser/Search/CharacterSearchParser.php b/src/Parser/Search/CharacterSearchParser.php index f9fb4c4f..6b165ae9 100644 --- a/src/Parser/Search/CharacterSearchParser.php +++ b/src/Parser/Search/CharacterSearchParser.php @@ -45,6 +45,13 @@ public function getModel(): CharacterSearch */ public function getResults(): array { + $probrem = $this->crawler + ->filterXPath('//div[@id="content"]/table/tr/td[1][contains(text(), "There were some probrems")]'); + + if ($probrem->count()) { + return []; + } + return $this->crawler ->filterXPath('//div[@id="content"]/table/tr') ->each( @@ -61,12 +68,33 @@ function (Crawler $c) { public function getLastPage(): int { $pages = $this->crawler - ->filterXPath('//div[@id="content"]/div[@class="borderClass"][1]/div/span/a'); + ->filterXPath('//div[@id="content"]/div[@class="borderClass"][1]/div/span'); if (!$pages->count()) { return 1; } - return (int)$pages->last()->text(); + $pages = explode(' ', $pages->text()); + + return (int) str_replace(['[', ']'], '', end($pages)); + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//div[contains(@class, "normal_header")]/div/div/span'); + + if (!$pages->count()) { + return false; + } + + if (preg_match('~\[\d+]\s(\d+)~', $pages->text())) { + return true; + } + + return false; } } diff --git a/src/Parser/Search/MangaSearchParser.php b/src/Parser/Search/MangaSearchParser.php index 452204d8..1b73edc6 100644 --- a/src/Parser/Search/MangaSearchParser.php +++ b/src/Parser/Search/MangaSearchParser.php @@ -69,12 +69,33 @@ function (Crawler $c) { public function getLastPage(): int { $pages = $this->crawler - ->filterXPath('//div[contains(@class, "normal_header")]/div/div/span/a'); + ->filterXPath('//div[contains(@class, "normal_header")]/div/div/span'); if (!$pages->count()) { return 1; } - return (int)$pages->last()->text(); + $pages = explode(' ', $pages->text()); + + return (int) str_replace(['[', ']'], '', end($pages)); + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//div[contains(@class, "normal_header")]/div/div/span'); + + if (!$pages->count()) { + return false; + } + + if (preg_match('~\[\d+]\s(\d+)~', $pages->text())) { + return true; + } + + return false; } } diff --git a/src/Parser/Search/UserSearchParser.php b/src/Parser/Search/UserSearchParser.php new file mode 100644 index 00000000..06bf4dfe --- /dev/null +++ b/src/Parser/Search/UserSearchParser.php @@ -0,0 +1,117 @@ +crawler = $crawler; + } + + /** + * @return UserSearch + * @throws \Exception + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getModel(): UserSearch + { + return UserSearch::fromParser($this); + } + + /** + * @return UserSearchListItem[] + * @throws \Exception + * @throws \RuntimeException + * @throws \InvalidArgumentException + */ + public function getResults(): array + { + // Check if it's the main page + // For `getRecentlyOnlineUsers` + $node = $this->crawler + ->filterXPath('//*[@id="content"]/table/tr/td[1]/table/tr/td'); + + // User search page + if (!$node->count()) { + $node = $this->crawler + ->filterXPath('//*[@id="content"]/table/tr/td'); + } + + $data = $node + ->each(function (Crawler $c) { + return (new UserSearchListItemParser($c))->getModel(); + }); + + // If only a single result is found, the $data array will be empty + // (redirect occurs here to the User Page) + if (empty($data)) { + $data = $this->crawler + ->each( + function (Crawler $c) { + return UserSearchListItem::fromUserSearchParser(new UserProfileParser($c)); + } + ); + } + + return $data; + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//div[@id="content"]/div[@class="borderClass"][1]/div/span'); + + if (!$pages->count()) { + return 1; + } + + $pages = explode(' ', $pages->text()); + + return (int) str_replace(['[', ']'], '', end($pages)); + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//div[@id="content"]/div[@class="borderClass"][1]/div/span'); + + if (!$pages->count()) { + return false; + } + + if (preg_match('~\[\d+]\s(\d+)~', $pages->text())) { + return true; + } + + return false; + } +} diff --git a/src/Parser/Top/TopAnimeParser.php b/src/Parser/Top/TopAnimeParser.php index 5464b605..8af3a282 100644 --- a/src/Parser/Top/TopAnimeParser.php +++ b/src/Parser/Top/TopAnimeParser.php @@ -3,6 +3,7 @@ namespace Jikan\Parser\Top; use Jikan\Model\Top\TopAnime; +use Jikan\Model\Top\TopAnimeListItem; use Symfony\Component\DomCrawler\Crawler; /** @@ -17,7 +18,6 @@ class TopAnimeParser */ private $crawler; - /** * CharacterListItemParser constructor. * @@ -29,18 +29,61 @@ public function __construct(Crawler $crawler) } /** - * @return TopAnime[] + * @return TopAnime + * @throws \Exception * @throws \RuntimeException * @throws \InvalidArgumentException */ - public function getTopAnime(): array + public function getModel(): TopAnime + { + return TopAnime::fromParser($this); + } + + /** + * @return array + */ + public function getResults(): array { return $this->crawler ->filterXPath('//tr[@class="ranking-list"]') ->each( function (Crawler $crawler) { - return TopAnime::fromParser(new TopListItemParser($crawler)); + return TopAnimeListItem::fromParser(new TopListItemParser($crawler)); } ); } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[4]/h2/span[1]/a[contains(@class, "next")]'); + + if (!$pages->count()) { + return 1; + } + + $page = ((int) preg_replace('~\?limit=(\d+)~', '$1', $pages->attr('href'))) / 50; + + return $page + 1; + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[4]/h2/span[1]/a[contains(@class, "next")]'); + + + if ($pages->count()) { + return true; + } + + return false; + } } diff --git a/src/Parser/Top/TopCharactersParser.php b/src/Parser/Top/TopCharactersParser.php index cef1a381..2658daf4 100644 --- a/src/Parser/Top/TopCharactersParser.php +++ b/src/Parser/Top/TopCharactersParser.php @@ -2,7 +2,9 @@ namespace Jikan\Parser\Top; -use Jikan\Model\Top\TopCharacter; +use Jikan\Model\Top\TopCharacterListItem; +use Jikan\Model\Top\TopCharacters; +use Jikan\Model\Top\TopPeople; use Symfony\Component\DomCrawler\Crawler; /** @@ -29,18 +31,62 @@ public function __construct(Crawler $crawler) } /** - * @return TopCharacter[] + * @return TopCharacters + * @throws \Exception * @throws \RuntimeException * @throws \InvalidArgumentException */ - public function getTopCharacters(): array + public function getModel(): TopCharacters + { + return TopCharacters::fromParser($this); + } + + /** + * @return array + */ + public function getResults(): array { return $this->crawler ->filterXPath('//tr[@class="ranking-list"]') ->each( function (Crawler $crawler) { - return TopCharacter::fromParser(new TopListItemParser($crawler)); + return TopCharacterListItem::fromParser(new TopListItemParser($crawler)); } ); } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/h2/div/span/a[contains(@class, "next")]'); + + if (!$pages->count()) { + return 1; + } + + preg_match('~\?limit=(\d+)$~', $pages->attr('href'), $page); + $page = (int) $page[1] / 50; + + return $page + 1; + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/h2/div/span/a[contains(@class, "next")]'); + + + if ($pages->count()) { + return true; + } + + return false; + } } diff --git a/src/Parser/Top/TopListItemParser.php b/src/Parser/Top/TopListItemParser.php index 2d768994..34313bf4 100644 --- a/src/Parser/Top/TopListItemParser.php +++ b/src/Parser/Top/TopListItemParser.php @@ -39,7 +39,6 @@ public function __construct(Crawler $crawler) /** * @return \Jikan\Model\Common\MalUrl * @throws \InvalidArgumentException - * @throws ParserException */ public function getMalUrl(): MalUrl { diff --git a/src/Parser/Top/TopMangaParser.php b/src/Parser/Top/TopMangaParser.php index 70e5b4c9..b430c7e8 100644 --- a/src/Parser/Top/TopMangaParser.php +++ b/src/Parser/Top/TopMangaParser.php @@ -3,6 +3,7 @@ namespace Jikan\Parser\Top; use Jikan\Model\Top\TopManga; +use Jikan\Model\Top\TopMangaListItem; use Symfony\Component\DomCrawler\Crawler; /** @@ -29,18 +30,61 @@ public function __construct(Crawler $crawler) } /** - * @return TopManga[] + * @return TopManga + * @throws \Exception * @throws \RuntimeException * @throws \InvalidArgumentException */ - public function getTopManga(): array + public function getModel(): TopManga + { + return TopManga::fromParser($this); + } + + /** + * @return array + */ + public function getResults(): array { return $this->crawler ->filterXPath('//tr[@class="ranking-list"]') ->each( function (Crawler $crawler) { - return TopManga::fromParser(new TopListItemParser($crawler)); + return TopMangaListItem::fromParser(new TopListItemParser($crawler)); } ); } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[4]/h2/span[1]/a[contains(@class, "next")]'); + + if (!$pages->count()) { + return 1; + } + + $page = ((int) preg_replace('~\?limit=(\d+)~', '$1', $pages->attr('href'))) / 50; + + return $page + 1; + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/div[4]/h2/span[1]/a[contains(@class, "next")]'); + + + if ($pages->count()) { + return true; + } + + return false; + } } diff --git a/src/Parser/Top/TopPeopleParser.php b/src/Parser/Top/TopPeopleParser.php index 824bdedd..90814fcf 100644 --- a/src/Parser/Top/TopPeopleParser.php +++ b/src/Parser/Top/TopPeopleParser.php @@ -2,7 +2,8 @@ namespace Jikan\Parser\Top; -use Jikan\Model\Top\TopPerson; +use Jikan\Model\Top\TopPeople; +use Jikan\Model\Top\TopPersonListItem; use Symfony\Component\DomCrawler\Crawler; /** @@ -29,18 +30,62 @@ public function __construct(Crawler $crawler) } /** - * @return TopPerson[] + * @return TopPeople + * @throws \Exception * @throws \RuntimeException * @throws \InvalidArgumentException */ - public function getTopPeople(): array + public function getModel(): TopPeople + { + return TopPeople::fromParser($this); + } + + /** + * @return array + */ + public function getResults(): array { return $this->crawler ->filterXPath('//tr[@class="ranking-list"]') ->each( function (Crawler $crawler) { - return TopPerson::fromParser(new TopListItemParser($crawler)); + return TopPersonListItem::fromParser(new TopListItemParser($crawler)); } ); } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getLastPage(): int + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/h2/div/span/a[contains(@class, "next")]'); + + if (!$pages->count()) { + return 1; + } + + preg_match('~\?limit=(\d+)$~', $pages->attr('href'), $page); + $page = (int) $page[1] / 50; + + return $page + 1; + } + + /** + * @return bool + */ + public function getHasNextPage(): bool + { + $pages = $this->crawler + ->filterXPath('//*[@id="content"]/h2/div/span/a[contains(@class, "next")]'); + + + if ($pages->count()) { + return true; + } + + return false; + } } diff --git a/src/Parser/User/ClubParser.php b/src/Parser/User/ClubParser.php new file mode 100644 index 00000000..0fb5a610 --- /dev/null +++ b/src/Parser/User/ClubParser.php @@ -0,0 +1,51 @@ +crawler = $crawler; + } + + /** + * @return array + * @throws \InvalidArgumentException + */ + public function getClubs(): array + { + $node = $this->crawler + ->filterXPath('//*[@id="content"]/table/tr/td[2]/ol/li'); + + return $node->each(function (Crawler $crawler) { + return Model\Common\ClubMeta::factory( + Parser::clubIdFromUrl( + $crawler->filterXPath('//a')->attr('href') + ), + $crawler->filterXPath('//a')->text(), + Constants::BASE_URL . $crawler->filterXPath('//a')->attr('href') + ); + }); + } +} diff --git a/src/Parser/Watch/PromotionalVideoListItemParser.php b/src/Parser/Watch/PromotionalVideoListItemParser.php new file mode 100644 index 00000000..366c0893 --- /dev/null +++ b/src/Parser/Watch/PromotionalVideoListItemParser.php @@ -0,0 +1,114 @@ +crawler = $crawler; + } + + /** + * @return EpisodeListItem + * @throws \Exception + * @throws \RuntimeException + */ + public function getModel(): EpisodeListItem + { + return EpisodeListItem::fromParser($this); + } + + /** + * @return int + * @throws \InvalidArgumentException + */ + public function getId(): int + { + return Parser::idFromUrl($this->getUrl()); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getUrl(): string + { + $node = $this->crawler->filterXPath('//div[@class="video-info-title"]/a[2]'); + return $node->attr('href'); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getTitle(): string + { + $node = $this->crawler->filterXPath('//div[@class="video-info-title"]/a[2]'); + return $node->text(); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImageUrl(): string + { + return Parser::parseImageQuality( + $this->crawler->filterXPath('//div[contains(@class, "video-list")]/a')->attr('data-bg') + ); + } + + /** + * @return string + * @throws \InvalidArgumentException + */ + public function getImages(): string + { + return Parser::parseImageQuality( + $this->crawler->filterXPath('//div[contains(@class, "video-list")]/a')->attr('data-bg') + ); + } + + /** + * @return YoutubeMeta + * @throws \InvalidArgumentException + */ + public function getPromoMedia(): YoutubeMeta + { + return YoutubeMeta::factory( + $this->crawler->filterXPath('//div[contains(@class, "video-list")]/a')->attr('href') + ); + } + + public function getPromoTitle(): string + { + $node = $this->crawler->filterXPath(' + //div[contains(@class, "video-list")]/a/div[contains(@class, "info-container")]/span + '); + return $node->text(); + } +} diff --git a/src/Parser/Watch/WatchEpisodesParser.php b/src/Parser/Watch/WatchEpisodesParser.php new file mode 100644 index 00000000..a2e8afff --- /dev/null +++ b/src/Parser/Watch/WatchEpisodesParser.php @@ -0,0 +1,50 @@ +crawler = $crawler; + } + + public function getModel(): Model\Watch\Episodes + { + return Model\Watch\Episodes::fromParser($this); + } + + public function getResults() : array + { + $node = $this->crawler->filterXPath( + '//*[@id="content"]/div[3]/div/div[contains(@class, "video-list-outer-vertical")] + ' + ); + + if (!$node->count()) { + return []; + } + + return $node->each(function (Crawler $crawler) { + return Model\Watch\EpisodeListItem::fromParser(new EpisodeListItemParser($crawler)); + }); + } +} diff --git a/src/Parser/Watch/WatchPromotionalVideosParser.php b/src/Parser/Watch/WatchPromotionalVideosParser.php new file mode 100644 index 00000000..bb53c440 --- /dev/null +++ b/src/Parser/Watch/WatchPromotionalVideosParser.php @@ -0,0 +1,81 @@ +crawler = $crawler; + } + + public function getModel(): Model\Watch\PromotionalVideos + { + return Model\Watch\PromotionalVideos::fromParser($this); + } + + public function getResults() : array + { + $node = $this->crawler->filterXPath( + '//*[@id="content"]/div[3]/div/div[contains(@class, "video-list-outer-vertical")]' + ); + + if (!$node->count()) { + return []; + } + + return $node->each(function (Crawler $crawler) { + return Model\Watch\PromotionalVideoListItem::fromParser(new PromotionalVideoListItemParser($crawler)); + }); + } + + public function getHasNextPage() : bool + { + $node = $this->crawler->filterXPath( + '//*[@id="content"]/div[contains(@class, "pagination")]/a[contains(text(), "More")]' + ); + + if ($node->count()) { + return true; + } + + return false; + } + + public function getLastVisiblePage() : int + { + $node = $this->crawler->filterXPath( + '//*[@id="content"]/div[contains(@class, "pagination")]/span[@class="link-blue-box"]' + ); + + if (!$node->count()) { + return 1; + } + + $currentPage = (int) $node->text(); + + if (!$this->getHasNextpage()) { + return $currentPage; + } + + return $currentPage + 1; + } +} diff --git a/src/Request/Anime/AnimeNewsRequest.php b/src/Request/Anime/AnimeNewsRequest.php index bbc92dcf..a43a80dd 100644 --- a/src/Request/Anime/AnimeNewsRequest.php +++ b/src/Request/Anime/AnimeNewsRequest.php @@ -16,14 +16,20 @@ class AnimeNewsRequest implements RequestInterface */ private $id; + /** + * @var int + */ + private $page; + /** * AnimeNewsRequest constructor. * * @param int $id */ - public function __construct(int $id) + public function __construct(int $id, ?int $page = 1) { $this->id = $id; + $this->page = $page; } /** @@ -31,7 +37,7 @@ public function __construct(int $id) */ public function getPath(): string { - return sprintf('https://myanimelist.net/anime/%s/_/news', $this->id); + return sprintf('https://myanimelist.net/anime/%d/_/news?p=%d', $this->id, $this->page); } /** diff --git a/src/Request/Magazine/MagazinesRequest.php b/src/Request/Magazine/MagazinesRequest.php index 78a98b12..b32700a6 100644 --- a/src/Request/Magazine/MagazinesRequest.php +++ b/src/Request/Magazine/MagazinesRequest.php @@ -9,7 +9,7 @@ * * @package Jikan\Request */ -class MagazinesRequest extends \Jikan\Request\Magazine\MagazineRequest implements RequestInterface +class MagazinesRequest implements RequestInterface { /** * @return string diff --git a/src/Request/Manga/MangaNewsRequest.php b/src/Request/Manga/MangaNewsRequest.php index 9f130f1e..8870e209 100644 --- a/src/Request/Manga/MangaNewsRequest.php +++ b/src/Request/Manga/MangaNewsRequest.php @@ -16,14 +16,20 @@ class MangaNewsRequest implements RequestInterface */ private $id; + /** + * @var int + */ + private $page; + /** * MangaNewsRequest constructor. * * @param int $id */ - public function __construct(int $id) + public function __construct(int $id, ?int $page = 1) { $this->id = $id; + $this->page = $page; } /** @@ -31,7 +37,7 @@ public function __construct(int $id) */ public function getPath(): string { - return sprintf('https://myanimelist.net/manga/%s/_/news', $this->id); + return sprintf('https://myanimelist.net/manga/%s/_/news?p=%d', $this->id, $this->page); } /** diff --git a/src/Request/Top/TopReviewsRequest.php b/src/Request/Reviews/RecentReviewsRequest.php similarity index 78% rename from src/Request/Top/TopReviewsRequest.php rename to src/Request/Reviews/RecentReviewsRequest.php index 0d232579..30174e59 100644 --- a/src/Request/Top/TopReviewsRequest.php +++ b/src/Request/Reviews/RecentReviewsRequest.php @@ -1,6 +1,6 @@ page = $page; @@ -38,9 +38,9 @@ public function __construct(string $type = Constants::TOP_REVIEW_BEST_VOTED, int if (!\in_array( $type, [ - Constants::TOP_REVIEW_BEST_VOTED, - Constants::TOP_REVIEW_ANIME, - Constants::TOP_REVIEW_MANGA, + Constants::RECENT_REVIEW_BEST_VOTED, + Constants::RECENT_REVIEW_ANIME, + Constants::RECENT_REVIEW_MANGA, ], true ) @@ -59,7 +59,7 @@ public function __construct(string $type = Constants::TOP_REVIEW_BEST_VOTED, int */ public function getPath(): string { - if ($this->type === Constants::TOP_REVIEW_BEST_VOTED) { + if ($this->type === Constants::RECENT_REVIEW_BEST_VOTED) { return 'https://myanimelist.net/reviews.php?'.http_build_query( [ 'p' => $this->page, diff --git a/src/Request/Search/AnimeSearchRequest.php b/src/Request/Search/AnimeSearchRequest.php index b3ad5f83..a20c7a1b 100644 --- a/src/Request/Search/AnimeSearchRequest.php +++ b/src/Request/Search/AnimeSearchRequest.php @@ -102,8 +102,8 @@ public function __construct(?string $query = null, int $page = 1) $querySize = strlen($this->query); - if ($querySize > 0 & $querySize < 3) { - throw new BadResponseException('Search queries requires at least 3 characters'); + if ($querySize > 0 && $querySize < 3) { + throw new BadResponseException('Search with queries require at least 3 characters'); } } diff --git a/src/Request/Search/CharacterSearchRequest.php b/src/Request/Search/CharacterSearchRequest.php index 86706586..2358def5 100644 --- a/src/Request/Search/CharacterSearchRequest.php +++ b/src/Request/Search/CharacterSearchRequest.php @@ -47,8 +47,8 @@ public function __construct(?string $query = null, int $page = 1) $querySize = strlen($this->query); - if ($querySize > 0 & $querySize < 3) { - throw new BadResponseException('Search queries requires at least 3 characters'); + if ($querySize > 0 && $querySize < 3) { + throw new BadResponseException('Search with queries require at least 3 characters'); } } diff --git a/src/Request/Search/MangaSearchRequest.php b/src/Request/Search/MangaSearchRequest.php index 9640101c..ecac503c 100644 --- a/src/Request/Search/MangaSearchRequest.php +++ b/src/Request/Search/MangaSearchRequest.php @@ -97,8 +97,8 @@ public function __construct(?string $query = null, int $page = 1) $querySize = strlen($this->query); - if ($querySize > 0 & $querySize < 3) { - throw new BadResponseException('Search queries requires at least 3 characters'); + if ($querySize > 0 && $querySize < 3) { + throw new BadResponseException('Search with queries require at least 3 characters'); } } diff --git a/src/Request/Search/PersonSearchRequest.php b/src/Request/Search/PersonSearchRequest.php index f0525780..e4713029 100644 --- a/src/Request/Search/PersonSearchRequest.php +++ b/src/Request/Search/PersonSearchRequest.php @@ -47,8 +47,8 @@ public function __construct(?string $query = null, int $page = 1) $querySize = strlen($this->query); - if ($querySize > 0 & $querySize < 3) { - throw new BadResponseException('Search queries requires at least 3 characters'); + if ($querySize > 0 && $querySize < 3) { + throw new BadResponseException('Search with queries require at least 3 characters'); } } diff --git a/src/Request/User/RecentlyOnlineUsersRequest.php b/src/Request/User/RecentlyOnlineUsersRequest.php new file mode 100644 index 00000000..65d90564 --- /dev/null +++ b/src/Request/User/RecentlyOnlineUsersRequest.php @@ -0,0 +1,22 @@ +jikan->getTopAnime(new \Jikan\Request\Top\TopAnimeRequest()); self::assertCount(50, $anime); - self::assertContainsOnlyInstancesOf(TopAnime::class, $anime); + self::assertContainsOnlyInstancesOf(TopAnimeListItem::class, $anime); self::assertContains('Fullmetal Alchemist: Brotherhood', $anime); self::assertContains('Mushishi Zoku Shou: Suzu no Shizuku', $anime); } @@ -320,7 +320,7 @@ public function it_gets_top_manga() { $manga = $this->jikan->getTopManga(new \Jikan\Request\Top\TopMangaRequest()); self::assertCount(50, $manga); - self::assertContainsOnlyInstancesOf(TopManga::class, $manga); + self::assertContainsOnlyInstancesOf(TopMangaListItem::class, $manga); self::assertContains('Berserk', $manga); self::assertContains('Shigatsu wa Kimi no Uso', $manga); } @@ -333,7 +333,7 @@ public function it_gets_top_characters() { $characters = $this->jikan->getTopCharacters(new \Jikan\Request\Top\TopCharactersRequest()); self::assertCount(50, $characters); - self::assertContainsOnlyInstancesOf(TopCharacter::class, $characters); + self::assertContainsOnlyInstancesOf(TopCharacterListItem::class, $characters); self::assertContains('Lamperouge, Lelouch', $characters); self::assertContains('Usui, Takumi', $characters); } @@ -346,7 +346,7 @@ public function it_gets_top_people() { $people = $this->jikan->getTopPeople(new \Jikan\Request\Top\TopPeopleRequest()); self::assertCount(50, $people); - self::assertContainsOnlyInstancesOf(TopPerson::class, $people); + self::assertContainsOnlyInstancesOf(TopPersonListItem::class, $people); self::assertContains('Hanazawa, Kana', $people); self::assertContains('Asano, Inio', $people); }