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
This commit is contained in:
Timothy Warren 2018-08-09 11:34:02 -04:00
parent d1421d2eb2
commit 49295148d1
9 changed files with 57 additions and 18 deletions

View File

@ -25,7 +25,7 @@ use Aviat\AnimeClient\API\{
HummingbirdClient, HummingbirdClient,
ListItemInterface ListItemInterface
}; };
use Aviat\AnimeClient\Types\AbstractType; use Aviat\AnimeClient\Types\FormItemData;
use Aviat\Ion\Di\ContainerAware; use Aviat\Ion\Di\ContainerAware;
use Aviat\Ion\Json; use Aviat\Ion\Json;
@ -112,7 +112,7 @@ final class ListItem implements ListItemInterface {
return Json::decode(wait($response->getBody())); 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(); $authHeader = $this->getAuthHeader();
$requestData = [ $requestData = [

View File

@ -40,6 +40,7 @@ use Aviat\AnimeClient\Types\{
AbstractType, AbstractType,
Anime, Anime,
FormItem, FormItem,
FormItemData,
AnimeListItem, AnimeListItem,
MangaPage MangaPage
}; };

View File

@ -125,13 +125,13 @@ final class AnimeListTransformer extends AbstractTransformer {
$untransformed = new AnimeFormItem([ $untransformed = new AnimeFormItem([
'id' => $item['id'], 'id' => $item['id'],
'mal_id' => $item['mal_id'] ?? NULL, 'mal_id' => $item['mal_id'] ?? NULL,
'data' => new AnimeFormItemData([ 'data' => [
'status' => $item['watching_status'], 'status' => $item['watching_status'],
'reconsuming' => $rewatching, 'reconsuming' => $rewatching,
'reconsumeCount' => $item['rewatched'], 'reconsumeCount' => $item['rewatched'],
'notes' => $item['notes'], 'notes' => $item['notes'],
'private' => $privacy 'private' => $privacy
]) ]
]); ]);
if (is_numeric($item['episodes_watched']) && $item['episodes_watched'] > 0) if (is_numeric($item['episodes_watched']) && $item['episodes_watched'] > 0)

View File

@ -17,7 +17,7 @@
namespace Aviat\AnimeClient\API; namespace Aviat\AnimeClient\API;
use Amp\Artax\Request; use Amp\Artax\Request;
use Aviat\AnimeClient\Types\AbstractType; use Aviat\AnimeClient\Types\FormItemData;
/** /**
* Common interface for anime and manga list item CRUD * Common interface for anime and manga list item CRUD
@ -44,10 +44,10 @@ interface ListItemInterface {
* Update a list item * Update a list item
* *
* @param string $id - The id of the list item to update * @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 * @return Request
*/ */
public function update(string $id, AbstractType $data): Request; public function update(string $id, FormItemData $data): Request;
/** /**
* Delete a list item * Delete a list item

View File

@ -20,6 +20,7 @@ use Aviat\AnimeClient\Controller as BaseController;
use Aviat\AnimeClient\API\Kitsu\Transformer\AnimeListTransformer; use Aviat\AnimeClient\API\Kitsu\Transformer\AnimeListTransformer;
use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Kitsu as KitsuWatchingStatus; use Aviat\AnimeClient\API\Enum\AnimeWatchingStatus\Kitsu as KitsuWatchingStatus;
use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus; use Aviat\AnimeClient\API\Mapping\AnimeWatchingStatus;
use Aviat\AnimeClient\Types\AnimeFormItem;
use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\ContainerInterface;
use Aviat\Ion\Json; use Aviat\Ion\Json;
use Aviat\Ion\StringWrapper; use Aviat\Ion\StringWrapper;
@ -201,7 +202,7 @@ final class Anime extends BaseController {
// large form-based updates // large form-based updates
$transformer = new AnimeListTransformer(); $transformer = new AnimeListTransformer();
$postData = $transformer->untransform($data); $postData = $transformer->untransform($data);
$fullResult = $this->model->updateLibraryItem($postData); $fullResult = $this->model->updateLibraryItem(new AnimeFormItem($postData));
if ($fullResult['statusCode'] === 200) if ($fullResult['statusCode'] === 200)
{ {
@ -232,7 +233,7 @@ final class Anime extends BaseController {
$data = $this->request->getParsedBody(); $data = $this->request->getParsedBody();
} }
$response = $this->model->updateLibraryItem($data); $response = $this->model->updateLibraryItem(new AnimeFormItem($data));
$this->cache->clear(); $this->cache->clear();
$this->outputJSON($response['body'], $response['statusCode']); $this->outputJSON($response['body'], $response['statusCode']);

View File

@ -34,12 +34,24 @@ abstract class AbstractType implements ArrayAccess {
/** /**
* Sets the properties by using the constructor * 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) { $typeKeys = array_keys((array)$this);
$this->$key = $value; $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 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); $existing = json_encode($this);
throw new LogicException("Trying to set non-existent property: '$name'. Existing properties: $existing"); 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) public function __get($name)
{ {
if (property_exists($this, $name)) { if (property_exists($this, $name))
{
return $this->$name; return $this->$name;
} }
@ -127,6 +149,9 @@ abstract class AbstractType implements ArrayAccess {
*/ */
public function offsetUnset($offset): void public function offsetUnset($offset): void
{ {
// Do nothing! if ($this->offsetExists($offset))
{
unset($this->$offset);
}
} }
} }

View File

@ -19,4 +19,9 @@ namespace Aviat\AnimeClient\Types;
/** /**
* Type representing an Anime object for display * 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);
}
}

View File

@ -23,5 +23,7 @@ abstract class FormItem extends AbstractType {
public $id; public $id;
public $mal_id; public $mal_id;
public $data; public $data;
abstract public function setData($value): void;
} }

View File

@ -19,5 +19,10 @@ namespace Aviat\AnimeClient\Types;
/** /**
* Form data for updating a Manga List item * 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);
}
}