From 58863a35d9502fc0030de9990c8461833ddb2b59 Mon Sep 17 00:00:00 2001 From: Zvonimir Maglica Date: Wed, 16 Oct 2019 00:27:27 +0200 Subject: [PATCH 1/2] added function to get HTTP status code. Few bugs fixed --- .gitignore | 3 ++- .php_cs.cache | 2 +- src/Api/Character.php | 8 ++++++-- src/Api/Episode.php | 4 +++- src/Api/Location.php | 4 +++- src/Model/AbstractModel.php | 10 ++++++++++ src/RickAndMortyApiWrapper.php | 1 + 7 files changed, 26 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 3b99cf4..a091e6b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ composer.lock docs vendor coverage -.idea \ No newline at end of file +.idea +.php_cs.cache \ No newline at end of file diff --git a/.php_cs.cache b/.php_cs.cache index 9a29cb9..46b4106 100644 --- a/.php_cs.cache +++ b/.php_cs.cache @@ -1 +1 @@ -{"php":"7.2.4","version":"2.15.3:v2.15.3#705490b0f282f21017d73561e9498d2b622ee34c","indent":" ","lineEnding":"\n","rules":{"blank_line_after_namespace":true,"braces":true,"class_definition":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"method_argument_space":{"ensure_fully_multiline":false},"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"encoding":true,"full_opening_tag":true,"array_syntax":{"syntax":"short"},"binary_operator_spaces":{"align_equals":false,"align_double_arrow":false},"cast_spaces":true,"combine_consecutive_unsets":true,"concat_space":{"spacing":"one"},"linebreak_after_opening_tag":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_extra_consecutive_blank_lines":true,"no_trailing_comma_in_singleline_array":true,"no_whitespace_in_blank_line":true,"no_spaces_around_offset":true,"no_unused_imports":true,"no_useless_else":true,"no_useless_return":true,"no_whitespace_before_comma_in_array":true,"normalize_index_brace":true,"phpdoc_indent":true,"phpdoc_to_comment":true,"phpdoc_trim":true,"single_quote":true,"ternary_to_null_coalescing":true,"trailing_comma_in_multiline_array":true,"trim_array_spaces":true,"blank_line_before_statement":true},"hashes":{"src\\Api\\AbstractApi.php":347679094,"src\\Api\\Character.php":3879616203,"src\\Api\\Location.php":2546914305,"src\\Model\\AbstractModel.php":984454081,"src\\Model\\Character.php":1124497613,"src\\Model\\Location.php":2697623879,"src\\RickAndMortyApiWrapper.php":2029558815,"tests\\ExampleTest.php":4233137363,"src\\Api\\Episode.php":27820038,"src\\Model\\Episode.php":186598213,"tests\\RickAndMortyApiWrapperTest.php":3270942840,"tests\\Unit\\Api\\CharacterTest.php":2196974728,"tests\\Unit\\RickAndMortyApiWrapperTest.php":1429713073}} \ No newline at end of file +{"php":"7.2.4","version":"2.15.3:v2.15.3#705490b0f282f21017d73561e9498d2b622ee34c","indent":" ","lineEnding":"\n","rules":{"blank_line_after_namespace":true,"braces":true,"class_definition":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"method_argument_space":{"ensure_fully_multiline":false},"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"encoding":true,"full_opening_tag":true,"array_syntax":{"syntax":"short"},"binary_operator_spaces":{"align_equals":false,"align_double_arrow":false},"cast_spaces":true,"combine_consecutive_unsets":true,"concat_space":{"spacing":"one"},"linebreak_after_opening_tag":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_extra_consecutive_blank_lines":true,"no_trailing_comma_in_singleline_array":true,"no_whitespace_in_blank_line":true,"no_spaces_around_offset":true,"no_unused_imports":true,"no_useless_else":true,"no_useless_return":true,"no_whitespace_before_comma_in_array":true,"normalize_index_brace":true,"phpdoc_indent":true,"phpdoc_to_comment":true,"phpdoc_trim":true,"single_quote":true,"ternary_to_null_coalescing":true,"trailing_comma_in_multiline_array":true,"trim_array_spaces":true,"blank_line_before_statement":true},"hashes":{"src\\Api\\AbstractApi.php":347679094,"src\\Api\\Character.php":2121936801,"src\\Api\\Location.php":3638972731,"src\\Model\\AbstractModel.php":2471819396,"src\\Model\\Character.php":1124497613,"src\\Model\\Location.php":2697623879,"src\\RickAndMortyApiWrapper.php":1955676743,"tests\\ExampleTest.php":4233137363,"src\\Api\\Episode.php":4087943247,"src\\Model\\Episode.php":186598213,"tests\\RickAndMortyApiWrapperTest.php":3270942840,"tests\\Unit\\Api\\CharacterTest.php":2196974728,"tests\\Unit\\RickAndMortyApiWrapperTest.php":1429713073,"tests\\Unit\\Api\\EpisodeTest.php":3864833709,"tests\\Unit\\Api\\LocationTest.php":2759447948}} \ No newline at end of file diff --git a/src/Api/Character.php b/src/Api/Character.php index ef24261..7228dbe 100644 --- a/src/Api/Character.php +++ b/src/Api/Character.php @@ -30,7 +30,9 @@ public function __construct(Client $client) */ public function getOrigin($id = null) { - return $this->get($id)->getOrigins(); + $origin = $this->get($id); + + return $origin->hasErrors() ? $origin : $origin->getOrigins(); } /** @@ -41,7 +43,9 @@ public function getOrigin($id = null) */ public function getLocation($id = null) { - return $this->get($id)->getLocations(); + $locations = $this->get($id); + + return $locations->hasErrors() ? $locations : $locations->getLocations(); } /** diff --git a/src/Api/Episode.php b/src/Api/Episode.php index 1d895c8..54a4cfa 100644 --- a/src/Api/Episode.php +++ b/src/Api/Episode.php @@ -26,6 +26,8 @@ public function __construct(Client $client) */ public function getCharacters($id = null) { - return $this->get($id)->getCharacters(); + $episodes = $this->get($id); + + return $episodes->hasErrors() ? $episodes : $episodes->getCharacters(); } } diff --git a/src/Api/Location.php b/src/Api/Location.php index e53f554..9180943 100644 --- a/src/Api/Location.php +++ b/src/Api/Location.php @@ -27,6 +27,8 @@ public function __construct(Client $client) */ public function getResidents($id = null) { - return $this->get($id)->getResidents(); + $locations = $this->get($id); + + return $locations->hasErrors() ? $locations : $locations->getResidents(); } } diff --git a/src/Model/AbstractModel.php b/src/Model/AbstractModel.php index 4a00e23..3e6f823 100644 --- a/src/Model/AbstractModel.php +++ b/src/Model/AbstractModel.php @@ -30,6 +30,16 @@ public function __construct($response, $parent) $this->info = $this->data['info'] ?? null; } + public function hasErrors() + { + return $this->response->getStatusCode() >= 400; + } + + public function getResponseStatusCode() + { + return $this->response->getStatusCode(); + } + public function toArray() { return $this->data; diff --git a/src/RickAndMortyApiWrapper.php b/src/RickAndMortyApiWrapper.php index bbe48e0..e52ce0b 100644 --- a/src/RickAndMortyApiWrapper.php +++ b/src/RickAndMortyApiWrapper.php @@ -21,6 +21,7 @@ class RickAndMortyApiWrapper */ private $options = [ 'base_uri' => 'https://rickandmortyapi.com/api/', + 'http_errors' => false, ]; /** From 7c55290f1d56c23903f9d8e3cbee05180b72e1ea Mon Sep 17 00:00:00 2001 From: Zvonimir Maglica Date: Wed, 16 Oct 2019 13:59:33 +0200 Subject: [PATCH 2/2] bug fixes and code improvments --- src/Api/AbstractApi.php | 31 +++++++++-------- src/Api/Character.php | 28 ++++++++-------- src/Model/AbstractModel.php | 61 +++++++++++++++++++++++++++++----- src/Model/Character.php | 27 ++++++--------- src/Model/Episode.php | 16 ++++----- src/Model/Location.php | 16 ++++----- src/RickAndMortyApiWrapper.php | 10 +++--- 7 files changed, 111 insertions(+), 78 deletions(-) diff --git a/src/Api/AbstractApi.php b/src/Api/AbstractApi.php index a874011..d02359d 100644 --- a/src/Api/AbstractApi.php +++ b/src/Api/AbstractApi.php @@ -44,6 +44,10 @@ public function sendRequest($uri = null, $arguments = null, $async = false) return $promise; } + /** + * @param null $ids + * @return mixed + */ public function get($ids = null) { $uri = $this->getUri($ids ?? $this->ids); @@ -60,7 +64,7 @@ public function all() * @param array $params * @return $this */ - public function where(array $params) + public function where(array $params) : self { if (!isset($this->arguments['query'])) { $this->arguments['query'] = []; @@ -78,12 +82,11 @@ public function where(array $params) } /** - * You can set ids and add additional filters and then execute API request - * + * You can set ids and add additional filters and then execute API requesr * @param $ids * @return AbstractApi */ - public function whereId($ids) + public function whereId($ids) : self { return $this->where(['id' => $ids]); } @@ -102,7 +105,7 @@ public function raw(string $uri) * * @return $this */ - public function clear() + public function clear() : self { $this->ids = null; $this->arguments['query'] = []; @@ -114,7 +117,7 @@ public function clear() * Get arguments/filters for API * @return array */ - public function getArguments() + public function getArguments() : array { return $this->arguments; } @@ -123,9 +126,9 @@ public function getArguments() * Set page for request * * @param int $page - * @return $this + * @return AbstractApi */ - public function setPage(int $page) + public function setPage(int $page) : self { $this->page = $page; $this->where(['page' => $page]); @@ -135,9 +138,9 @@ public function setPage(int $page) /** * Increment page to simulate pagination - * @return $this + * @return AbstractApi */ - public function nextPage() + public function nextPage() : self { $this->page++; $this->where(['page' => $this->page]); @@ -147,9 +150,9 @@ public function nextPage() /** * Decrement page to simulate pagination - * @return $this + * @return AbstractApi */ - public function previousPage() + public function previousPage() : self { /* * Minimum page number is 1 @@ -189,9 +192,9 @@ public function getUri($ids = null) * Example: whereName('Rick') will internally call where function with argument ['name' => 'Rick'] * @param $name * @param $arguments - * @return $this + * @return AbstractApi */ - public function __call($name, $arguments) + public function __call($name, $arguments) : self { if (strpos($name, 'where') !== 0) { throw new \BadFunctionCallException(); diff --git a/src/Api/Character.php b/src/Api/Character.php index 7228dbe..85218a3 100644 --- a/src/Api/Character.php +++ b/src/Api/Character.php @@ -51,9 +51,9 @@ public function getLocation($id = null) /** * Query to filter dead characters * - * @return $this + * @return Character */ - public function isDead() + public function isDead() : self { $this->where(['status' => 'dead']); @@ -63,9 +63,9 @@ public function isDead() /** * Query to filter alive characters * - * @return $this + * @return Character */ - public function isAlive() + public function isAlive() : self { $this->where(['status' => 'alive']); @@ -75,9 +75,9 @@ public function isAlive() /** * Query to filter characters with unknown status * - * @return $this + * @return Character */ - public function isStatusUnknown() + public function isStatusUnknown() : self { $this->where(['status' => 'unknown']); @@ -87,9 +87,9 @@ public function isStatusUnknown() /** * Query to filter female characters * - * @return $this + * @return Character */ - public function isFemale() + public function isFemale() : self { $this->where(['gender' => 'female']); @@ -99,9 +99,9 @@ public function isFemale() /** * Query to filter male characters * - * @return $this + * @return Character */ - public function isMale() + public function isMale() : self { $this->where(['gender' => 'male']); @@ -111,9 +111,9 @@ public function isMale() /** * Query to filter genderless characters * - * @return $this + * @return Character */ - public function isGenderless() + public function isGenderless() : self { $this->where(['gender' => 'genderless']); @@ -123,9 +123,9 @@ public function isGenderless() /** * Query to filter characters with unknown gender * - * @return $this + * @return Character */ - public function isGenderUnknown() + public function isGenderUnknown() : self { $this->where(['gender' => 'unknown']); diff --git a/src/Model/AbstractModel.php b/src/Model/AbstractModel.php index 3e6f823..356a569 100644 --- a/src/Model/AbstractModel.php +++ b/src/Model/AbstractModel.php @@ -30,22 +30,39 @@ public function __construct($response, $parent) $this->info = $this->data['info'] ?? null; } - public function hasErrors() + /** + * Check if there was errors on request + * @return bool + */ + public function hasErrors(): bool { return $this->response->getStatusCode() >= 400; } - public function getResponseStatusCode() + /** + * Get response status code + * + * @return int + */ + public function getResponseStatusCode(): int { return $this->response->getStatusCode(); } - public function toArray() + /** + * Get response data + * @return array + */ + public function toArray(): array { return $this->data; } - public function toJson() + /** + * Get data as json + * @return string + */ + public function toJson(): string { return json_encode($this->data); } @@ -54,7 +71,7 @@ public function toJson() * Check if is first page of response * @return bool */ - public function isFirstPage() + public function isFirstPage(): bool { if ($this->info && $this->info['prev']) { return false; @@ -68,7 +85,7 @@ public function isFirstPage() * * @return bool */ - public function isLastPage() + public function isLastPage(): bool { if ($this->info && $this->info['next']) { return false; @@ -81,7 +98,7 @@ public function isLastPage() * Get total number of records * @return int */ - public function count() + public function count(): int { if ($this->info) { return $this->info['count']; @@ -101,7 +118,7 @@ public function count() /** Get total number of pages * @return int */ - public function pages() + public function pages(): int { return $this->info['pages'] ?? 1; } @@ -132,6 +149,10 @@ public function next() return $this->parent->nextPage()->sendRequest(); } + /** + * Go to first page + * @return mixed + */ public function firstPage() { if ($this->info) { @@ -141,6 +162,11 @@ public function firstPage() return null; } + /** + * Go to desired page + * @param int $page + * @return mixed + */ public function goToPage(int $page) { if ($this->info) { @@ -148,6 +174,10 @@ public function goToPage(int $page) } } + /** + * Go to last page + * @return mixed + */ public function lastPage() { if ($this->info) { @@ -156,4 +186,19 @@ public function lastPage() return null; } + + /** + * Helper function to get ids from urls + * @param array $urls + * @return array + */ + public function parseIdsFromUrl(array $urls) : array + { + $ids = []; + foreach ($urls as $url) { + $ids[] = substr(strrchr($url, '/'), 1); + } + + return $ids; + } } diff --git a/src/Model/Character.php b/src/Model/Character.php index 4084794..aab5846 100644 --- a/src/Model/Character.php +++ b/src/Model/Character.php @@ -2,15 +2,17 @@ namespace Zmaglica\RickAndMortyApiWrapper\Model; +use Zmaglica\RickAndMortyApiWrapper\Api\AbstractApi; + class Character extends AbstractModel { /** * Get all locations without running API call. Useful if you want to perform additional filtering. * * @param bool $removeDuplicates - * @return array|\Zmaglica\RickAndMortyApiWrapper\Api\AbstractApi + * @return AbstractApi */ - public function locations($removeDuplicates = false) + public function locations($removeDuplicates = false) : AbstractApi { $ids = $this->extractIdsFromResponseBasedOnKey('location', $removeDuplicates); @@ -31,9 +33,9 @@ public function getLocations($removeDuplicates = false) * Get all origin locations. Useful if you want to perform additional filtering. * * @param bool $removeDuplicates - * @return array|\Zmaglica\RickAndMortyApiWrapper\Api\AbstractApi + * @return AbstractApi */ - public function origins($removeDuplicates = false) + public function origins($removeDuplicates = false) : AbstractApi { $ids = $this->extractIdsFromResponseBasedOnKey('origin', $removeDuplicates); @@ -55,9 +57,9 @@ public function getOrigins($removeDuplicates = false) * Get all episodes. Useful if you want to perform additional filtering. * * @param bool $removeDuplicates - * @return \Zmaglica\RickAndMortyApiWrapper\Api\AbstractApi + * @return AbstractApi */ - public function episodes($removeDuplicates = false) + public function episodes($removeDuplicates = false) : AbstractApi { $ids = $this->extractIdsFromResponseBasedOnKey('episode', $removeDuplicates); @@ -80,9 +82,8 @@ public function getEpisodes($removeDuplicates = false) * @param boolean $removeDuplicates * @return array */ - private function extractIdsFromResponseBasedOnKey($key, $removeDuplicates) + private function extractIdsFromResponseBasedOnKey($key, $removeDuplicates) : array { - $ids = []; $urls = []; if ($this->info) { $urls = array_column($this->data['results'], $key); @@ -96,14 +97,6 @@ private function extractIdsFromResponseBasedOnKey($key, $removeDuplicates) $urls = array_unique($urls); } - foreach ($urls as $url) { - $ids[] = substr(strrchr($url, '/'), 1); - ; - } - if (!$ids) { - return []; - } - - return $ids; + return $this->parseIdsFromUrl($urls); } } diff --git a/src/Model/Episode.php b/src/Model/Episode.php index 9b643e0..4fa76d7 100644 --- a/src/Model/Episode.php +++ b/src/Model/Episode.php @@ -2,14 +2,16 @@ namespace Zmaglica\RickAndMortyApiWrapper\Model; +use Zmaglica\RickAndMortyApiWrapper\Api\AbstractApi; + class Episode extends AbstractModel { /** * Get all characters without running API call. Useful if you want to perform additional filtering. * @param bool $removeDuplicates - * @return \Zmaglica\RickAndMortyApiWrapper\Api\AbstractApi + * @return AbstractApi */ - public function characters($removeDuplicates = false) + public function characters($removeDuplicates = false): AbstractApi { $ids = $this->extractIdsFromResponseBasedOnKey('characters', $removeDuplicates); @@ -32,9 +34,8 @@ public function getCharacters($removeDuplicates = false) * @param $removeDuplicates * @return array */ - private function extractIdsFromResponseBasedOnKey($key, $removeDuplicates) + private function extractIdsFromResponseBasedOnKey($key, $removeDuplicates): array { - $ids = []; if ($this->info) { $urls = array_column($this->data['results'], $key); // flatten array to single one because there can be multiple residents per location @@ -51,11 +52,6 @@ private function extractIdsFromResponseBasedOnKey($key, $removeDuplicates) $urls = array_unique($urls); } - foreach ($urls as $url) { - $ids[] = substr(strrchr($url, '/'), 1); - ; - } - - return $ids; + return $this->parseIdsFromUrl($urls); } } diff --git a/src/Model/Location.php b/src/Model/Location.php index e89304e..22d4899 100644 --- a/src/Model/Location.php +++ b/src/Model/Location.php @@ -2,14 +2,16 @@ namespace Zmaglica\RickAndMortyApiWrapper\Model; +use Zmaglica\RickAndMortyApiWrapper\Api\AbstractApi; + class Location extends AbstractModel { /** * Get all location residents without running API call. Useful if you want to perform additional filtering. * @param bool $removeDuplicates - * @return \Zmaglica\RickAndMortyApiWrapper\Api\AbstractApi + * @return AbstractApi */ - public function residents($removeDuplicates = false) + public function residents($removeDuplicates = false): AbstractApi { $ids = $this->extractIdsFromResponseBasedOnKey('residents', $removeDuplicates); @@ -32,9 +34,8 @@ public function getResidents($removeDuplicates = false) * @param $removeDuplicates * @return array */ - private function extractIdsFromResponseBasedOnKey($key, $removeDuplicates) + private function extractIdsFromResponseBasedOnKey($key, $removeDuplicates): array { - $ids = []; if ($this->info) { $urls = array_column($this->data['results'], $key); // flatten array to single one because there can be multiple residents per location @@ -51,11 +52,6 @@ private function extractIdsFromResponseBasedOnKey($key, $removeDuplicates) $urls = array_unique($urls); } - foreach ($urls as $url) { - $ids[] = substr(strrchr($url, '/'), 1); - ; - } - - return $ids; + return $this->parseIdsFromUrl($urls); } } diff --git a/src/RickAndMortyApiWrapper.php b/src/RickAndMortyApiWrapper.php index e52ce0b..de1d2c6 100644 --- a/src/RickAndMortyApiWrapper.php +++ b/src/RickAndMortyApiWrapper.php @@ -46,7 +46,7 @@ public function getClient(): Client * @param Client $client * @return RickAndMortyApiWrapper */ - public function setClient(Client $client): RickAndMortyApiWrapper + public function setClient(Client $client): self { $this->client = $client; @@ -66,7 +66,7 @@ public function getOptions(): array * @param array $options * @return RickAndMortyApiWrapper */ - public function setOptions(array $options): RickAndMortyApiWrapper + public function setOptions(array $options): self { $this->options = $options; @@ -77,7 +77,7 @@ public function setOptions(array $options): RickAndMortyApiWrapper * Wrapper for Character API * @return Character */ - public function character() + public function character(): Character { return new Character($this->client); } @@ -86,7 +86,7 @@ public function character() * Wrapper for Location API * @return Location */ - public function location() + public function location(): Location { return new Location($this->client); } @@ -95,7 +95,7 @@ public function location() * Wrapper for Episode API * @return Episode */ - public function episode() + public function episode(): Episode { return new Episode($this->client); }