From 1dc13701154aec5abce19f5811b21e23b102bb4f Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Thu, 9 Aug 2018 11:34:02 -0400 Subject: [PATCH] Update some types * Remove empty values from types for serialization, so that empty values are not sent with API requests * Allow use of explicit setters for more complex types --- src/API/Kitsu/ListItem.php | 4 +- src/API/Kitsu/Model.php | 1 + .../Transformer/AnimeListTransformer.php | 4 +- src/API/ListItemInterface.php | 6 +-- src/Controller/Anime.php | 5 ++- src/Types/AbstractType.php | 39 +++++++++++++++---- src/Types/AnimeFormItem.php | 7 +++- src/Types/FormItem.php | 2 + src/Types/MangaFormItem.php | 7 +++- 9 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/API/Kitsu/ListItem.php b/src/API/Kitsu/ListItem.php index bb7be57b..e91ca394 100644 --- a/src/API/Kitsu/ListItem.php +++ b/src/API/Kitsu/ListItem.php @@ -25,7 +25,7 @@ use Aviat\AnimeClient\API\{ HummingbirdClient, ListItemInterface }; -use Aviat\AnimeClient\Types\AbstractType; +use Aviat\AnimeClient\Types\FormItemData; use Aviat\Ion\Di\ContainerAware; use Aviat\Ion\Json; @@ -112,7 +112,7 @@ final class ListItem implements ListItemInterface { return Json::decode(wait($response->getBody())); } - public function update(string $id, AbstractType $data): Request + public function update(string $id, FormItemData $data): Request { $authHeader = $this->getAuthHeader(); $requestData = [ diff --git a/src/API/Kitsu/Model.php b/src/API/Kitsu/Model.php index 42963390..634c5462 100644 --- a/src/API/Kitsu/Model.php +++ b/src/API/Kitsu/Model.php @@ -40,6 +40,7 @@ use Aviat\AnimeClient\Types\{ AbstractType, Anime, FormItem, + FormItemData, AnimeListItem, MangaPage }; diff --git a/src/API/Kitsu/Transformer/AnimeListTransformer.php b/src/API/Kitsu/Transformer/AnimeListTransformer.php index 19b01952..ab73ac50 100644 --- a/src/API/Kitsu/Transformer/AnimeListTransformer.php +++ b/src/API/Kitsu/Transformer/AnimeListTransformer.php @@ -125,13 +125,13 @@ final class AnimeListTransformer extends AbstractTransformer { $untransformed = new AnimeFormItem([ 'id' => $item['id'], 'mal_id' => $item['mal_id'] ?? NULL, - 'data' => new AnimeFormItemData([ + 'data' => [ 'status' => $item['watching_status'], 'reconsuming' => $rewatching, 'reconsumeCount' => $item['rewatched'], 'notes' => $item['notes'], 'private' => $privacy - ]) + ] ]); if (is_numeric($item['episodes_watched']) && $item['episodes_watched'] > 0) diff --git a/src/API/ListItemInterface.php b/src/API/ListItemInterface.php index 9fbcde48..2fb6404a 100644 --- a/src/API/ListItemInterface.php +++ b/src/API/ListItemInterface.php @@ -17,7 +17,7 @@ namespace Aviat\AnimeClient\API; use Amp\Artax\Request; -use Aviat\AnimeClient\Types\AbstractType; +use Aviat\AnimeClient\Types\FormItemData; /** * Common interface for anime and manga list item CRUD @@ -44,10 +44,10 @@ interface ListItemInterface { * Update a list item * * @param string $id - The id of the list item to update - * @param AbstractType $data - The data with which to update the list item + * @param FormItemData $data - The data with which to update the list item * @return Request */ - public function update(string $id, AbstractType $data): Request; + public function update(string $id, FormItemData $data): Request; /** * Delete a list item diff --git a/src/Controller/Anime.php b/src/Controller/Anime.php index d1ccb05e..4fec2e7f 100644 --- a/src/Controller/Anime.php +++ b/src/Controller/Anime.php @@ -20,6 +20,7 @@ use Aviat\AnimeClient\Controller as BaseController; use Aviat\AnimeClient\API\Kitsu\Transformer\AnimeListTransformer; use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Kitsu as KitsuWatchingStatus; use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus; +use Aviat\AnimeClient\Types\AnimeFormItem; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Json; use Aviat\Ion\StringWrapper; @@ -201,7 +202,7 @@ final class Anime extends BaseController { // large form-based updates $transformer = new AnimeListTransformer(); $postData = $transformer->untransform($data); - $fullResult = $this->model->updateLibraryItem($postData); + $fullResult = $this->model->updateLibraryItem(new AnimeFormItem($postData)); if ($fullResult['statusCode'] === 200) { @@ -232,7 +233,7 @@ final class Anime extends BaseController { $data = $this->request->getParsedBody(); } - $response = $this->model->updateLibraryItem($data); + $response = $this->model->updateLibraryItem(new AnimeFormItem($data)); $this->cache->clear(); $this->outputJSON($response['body'], $response['statusCode']); diff --git a/src/Types/AbstractType.php b/src/Types/AbstractType.php index 664f3fde..f4dd427d 100644 --- a/src/Types/AbstractType.php +++ b/src/Types/AbstractType.php @@ -34,12 +34,24 @@ abstract class AbstractType implements ArrayAccess { /** * Sets the properties by using the constructor * - * @param array $data + * @param mixed $data */ - public function __construct(array $data = []) + public function __construct($data = []) { - foreach ($data as $key => $value) { - $this->$key = $value; + $typeKeys = array_keys((array)$this); + $dataKeys = array_keys((array)$data); + + $unsetKeys = array_diff($typeKeys, $dataKeys); + + foreach ($data as $key => $value) + { + $this->__set($key, $value); + } + + // Remove unset keys so that they aren't serialized + foreach ($unsetKeys as $k) + { + unset($this->$k); } } @@ -63,7 +75,16 @@ abstract class AbstractType implements ArrayAccess { */ public function __set($name, $value): void { - if (!property_exists($this, $name)) { + $setterMethod = 'set' . ucfirst($name); + + if (method_exists($this, $setterMethod)) + { + $this->$setterMethod($value); + return; + } + + if (!property_exists($this, $name)) + { $existing = json_encode($this); throw new LogicException("Trying to set non-existent property: '$name'. Existing properties: $existing"); @@ -80,7 +101,8 @@ abstract class AbstractType implements ArrayAccess { */ public function __get($name) { - if (property_exists($this, $name)) { + if (property_exists($this, $name)) + { return $this->$name; } @@ -127,6 +149,9 @@ abstract class AbstractType implements ArrayAccess { */ public function offsetUnset($offset): void { - // Do nothing! + if ($this->offsetExists($offset)) + { + unset($this->$offset); + } } } \ No newline at end of file diff --git a/src/Types/AnimeFormItem.php b/src/Types/AnimeFormItem.php index 69a72881..69a6f501 100644 --- a/src/Types/AnimeFormItem.php +++ b/src/Types/AnimeFormItem.php @@ -19,4 +19,9 @@ namespace Aviat\AnimeClient\Types; /** * Type representing an Anime object for display */ -final class AnimeFormItem extends FormItem { } +final class AnimeFormItem extends FormItem { + public function setData($value): void + { + $this->data = new AnimeFormItemData($value); + } +} diff --git a/src/Types/FormItem.php b/src/Types/FormItem.php index 084a1578..f5a3a5d8 100644 --- a/src/Types/FormItem.php +++ b/src/Types/FormItem.php @@ -23,5 +23,7 @@ abstract class FormItem extends AbstractType { public $id; public $mal_id; public $data; + + abstract public function setData($value): void; } diff --git a/src/Types/MangaFormItem.php b/src/Types/MangaFormItem.php index ecc0dcb9..6b630c1a 100644 --- a/src/Types/MangaFormItem.php +++ b/src/Types/MangaFormItem.php @@ -19,5 +19,10 @@ namespace Aviat\AnimeClient\Types; /** * Form data for updating a Manga List item */ -final class MangaFormItem extends FormItem { } +final class MangaFormItem extends FormItem { + public function setData($value): void + { + $this->data = new MangaFormItemData($value); + } +}