diff --git a/examples/01-blog/Blog/Type/CommentType.php b/examples/01-blog/Blog/Type/CommentType.php index b89aa54..cbcad4d 100644 --- a/examples/01-blog/Blog/Type/CommentType.php +++ b/examples/01-blog/Blog/Type/CommentType.php @@ -36,8 +36,9 @@ class CommentType extends ObjectType ]; }, 'resolveField' => function($value, $args, $context, ResolveInfo $info) { - if (method_exists($this, $info->fieldName)) { - return $this->{$info->fieldName}($value, $args, $context, $info); + $method = 'resolve' . ucfirst($info->fieldName); + if (method_exists($this, $method)) { + return $this->{$method}($value, $args, $context, $info); } else { return $value->{$info->fieldName}; } @@ -46,7 +47,7 @@ class CommentType extends ObjectType parent::__construct($config); } - public function author(Comment $comment) + public function resolveAuthor(Comment $comment) { if ($comment->isAnonymous) { return null; @@ -54,7 +55,7 @@ class CommentType extends ObjectType return DataSource::findUser($comment->authorId); } - public function parent(Comment $comment) + public function resolveParent(Comment $comment) { if ($comment->parentId) { return DataSource::findComment($comment->parentId); @@ -62,13 +63,13 @@ class CommentType extends ObjectType return null; } - public function replies(Comment $comment, $args) + public function resolveReplies(Comment $comment, $args) { $args += ['after' => null]; return DataSource::findReplies($comment->id, $args['limit'], $args['after']); } - public function totalReplyCount(Comment $comment) + public function resolveTotalReplyCount(Comment $comment) { return DataSource::countReplies($comment->id); } diff --git a/examples/01-blog/Blog/Type/StoryType.php b/examples/01-blog/Blog/Type/StoryType.php index 38cf73f..32cea4e 100644 --- a/examples/01-blog/Blog/Type/StoryType.php +++ b/examples/01-blog/Blog/Type/StoryType.php @@ -76,8 +76,9 @@ class StoryType extends ObjectType Types::node() ], 'resolveField' => function($value, $args, $context, ResolveInfo $info) { - if (method_exists($this, $info->fieldName)) { - return $this->{$info->fieldName}($value, $args, $context, $info); + $method = 'resolve' . ucfirst($info->fieldName); + if (method_exists($this, $method)) { + return $this->{$method}($value, $args, $context, $info); } else { return $value->{$info->fieldName}; } @@ -86,12 +87,12 @@ class StoryType extends ObjectType parent::__construct($config); } - public function author(Story $story) + public function resolveAuthor(Story $story) { return DataSource::findUser($story->authorId); } - public function affordances(Story $story, $args, AppContext $context) + public function resolveAffordances(Story $story, $args, AppContext $context) { $isViewer = $context->viewer === DataSource::findUser($story->authorId); $isLiked = DataSource::isLikedBy($story->id, $context->viewer->id); @@ -108,17 +109,17 @@ class StoryType extends ObjectType return $affordances; } - public function hasViewerLiked(Story $story, $args, AppContext $context) + public function resolveHasViewerLiked(Story $story, $args, AppContext $context) { return DataSource::isLikedBy($story->id, $context->viewer->id); } - public function totalCommentCount(Story $story) + public function resolveTotalCommentCount(Story $story) { return DataSource::countComments($story->id); } - public function comments(Story $story, $args) + public function resolveComments(Story $story, $args) { $args += ['after' => null]; return DataSource::findComments($story->id, $args['limit'], $args['after']); diff --git a/examples/01-blog/Blog/Type/UserType.php b/examples/01-blog/Blog/Type/UserType.php index 347da46..9960b62 100644 --- a/examples/01-blog/Blog/Type/UserType.php +++ b/examples/01-blog/Blog/Type/UserType.php @@ -45,8 +45,9 @@ class UserType extends ObjectType Types::node() ], 'resolveField' => function($value, $args, $context, ResolveInfo $info) { - if (method_exists($this, $info->fieldName)) { - return $this->{$info->fieldName}($value, $args, $context, $info); + $method = 'resolve' . ucfirst($info->fieldName); + if (method_exists($this, $method)) { + return $this->{$method}($value, $args, $context, $info); } else { return $value->{$info->fieldName}; } @@ -55,12 +56,12 @@ class UserType extends ObjectType parent::__construct($config); } - public function photo(User $user, $args) + public function resolvePhoto(User $user, $args) { return DataSource::getUserPhoto($user->id, $args['size']); } - public function lastStoryPosted(User $user) + public function resolveLastStoryPosted(User $user) { return DataSource::findLastStoryFor($user->id); } diff --git a/src/Utils/MixedStore.php b/src/Utils/MixedStore.php index 83342b6..76d5444 100644 --- a/src/Utils/MixedStore.php +++ b/src/Utils/MixedStore.php @@ -16,7 +16,12 @@ class MixedStore implements \ArrayAccess /** * @var array */ - private $scalarStore; + private $standardStore; + + /** + * @var array + */ + private $floatStore; /** * @var \SplObjectStorage @@ -51,17 +56,41 @@ class MixedStore implements \ArrayAccess /** * @var bool */ - private $nullValueIsSet = false; + private $nullValueIsSet; + + /** + * @var mixed + */ + private $trueValue; + + /** + * @var bool + */ + private $trueValueIsSet; + + /** + * @var mixed + */ + private $falseValue; + + /** + * @var bool + */ + private $falseValueIsSet; /** * MixedStore constructor. */ public function __construct() { - $this->scalarStore = []; + $this->standardStore = []; + $this->floatStore = []; $this->objectStore = new \SplObjectStorage(); $this->arrayKeys = []; $this->arrayValues = []; + $this->nullValueIsSet = false; + $this->trueValueIsSet = false; + $this->falseValueIsSet = false; } /** @@ -78,8 +107,17 @@ class MixedStore implements \ArrayAccess */ public function offsetExists($offset) { - if (is_scalar($offset)) { - return array_key_exists($offset, $this->scalarStore); + if (false === $offset) { + return $this->falseValueIsSet; + } + if (true === $offset) { + return $this->trueValueIsSet; + } + if (is_int($offset) || is_string($offset)) { + return array_key_exists($offset, $this->standardStore); + } + if (is_float($offset)) { + return array_key_exists((string) $offset, $this->floatStore); } if (is_object($offset)) { return $this->objectStore->offsetExists($offset); @@ -110,8 +148,17 @@ class MixedStore implements \ArrayAccess */ public function offsetGet($offset) { - if (is_scalar($offset)) { - return $this->scalarStore[$offset]; + if (true === $offset) { + return $this->trueValue; + } + if (false === $offset) { + return $this->falseValue; + } + if (is_int($offset) || is_string($offset)) { + return $this->standardStore[$offset]; + } + if (is_float($offset)) { + return $this->floatStore[(string)$offset]; } if (is_object($offset)) { return $this->objectStore->offsetGet($offset); @@ -147,8 +194,16 @@ class MixedStore implements \ArrayAccess */ public function offsetSet($offset, $value) { - if (is_scalar($offset)) { - $this->scalarStore[$offset] = $value; + if (false === $offset) { + $this->falseValue = $value; + $this->falseValueIsSet = true; + } else if (true === $offset) { + $this->trueValue = $value; + $this->trueValueIsSet = true; + } else if (is_int($offset) || is_string($offset)) { + $this->standardStore[$offset] = $value; + } else if (is_float($offset)) { + $this->floatStore[(string)$offset] = $value; } else if (is_object($offset)) { $this->objectStore[$offset] = $value; } else if (is_array($offset)) { @@ -173,8 +228,16 @@ class MixedStore implements \ArrayAccess */ public function offsetUnset($offset) { - if (is_scalar($offset)) { - unset($this->scalarStore[$offset]); + if (true === $offset) { + $this->trueValue = null; + $this->trueValueIsSet = false; + } else if (false === $offset) { + $this->falseValue = null; + $this->falseValueIsSet = false; + } else if (is_int($offset) || is_string($offset)) { + unset($this->standardStore[$offset]); + } else if (is_float($offset)) { + unset($this->floatStore[(string)$offset]); } else if (is_object($offset)) { $this->objectStore->offsetUnset($offset); } else if (is_array($offset)) { diff --git a/tests/Utils/MixedStoreTest.php b/tests/Utils/MixedStoreTest.php new file mode 100644 index 0000000..9ebfe6f --- /dev/null +++ b/tests/Utils/MixedStoreTest.php @@ -0,0 +1,126 @@ +mixedStore = new MixedStore(); + } + + public function getPossibleValues() + { + return [ + null, + false, + true, + '', + '0', + '1', + 'a', + [], + new \stdClass(), + function() {}, + new MixedStore() + ]; + } + + public function testAcceptsNullKeys() + { + foreach ($this->getPossibleValues() as $value) { + $this->assertAcceptsKeyValue(null, $value); + } + } + + public function testAcceptsBoolKeys() + { + foreach ($this->getPossibleValues() as $value) { + $this->assertAcceptsKeyValue(false, $value); + } + foreach ($this->getPossibleValues() as $value) { + $this->assertAcceptsKeyValue(true, $value); + } + } + + public function testAcceptsIntKeys() + { + foreach ($this->getPossibleValues() as $value) { + $this->assertAcceptsKeyValue(-100000, $value); + $this->assertAcceptsKeyValue(-1, $value); + $this->assertAcceptsKeyValue(0, $value); + $this->assertAcceptsKeyValue(1, $value); + $this->assertAcceptsKeyValue(1000000, $value); + } + } + + public function testAcceptsFloatKeys() + { + foreach ($this->getPossibleValues() as $value) { + $this->assertAcceptsKeyValue(-100000.5, $value); + $this->assertAcceptsKeyValue(-1.6, $value); + $this->assertAcceptsKeyValue(-0.0001, $value); + $this->assertAcceptsKeyValue(0.0000, $value); + $this->assertAcceptsKeyValue(0.0001, $value); + $this->assertAcceptsKeyValue(1.6, $value); + $this->assertAcceptsKeyValue(1000000.5, $value); + } + } + + public function testAcceptsArrayKeys() + { + foreach ($this->getPossibleValues() as $value) { + $this->assertAcceptsKeyValue([], $value); + $this->assertAcceptsKeyValue([null], $value); + $this->assertAcceptsKeyValue([[]], $value); + $this->assertAcceptsKeyValue([new \stdClass()], $value); + $this->assertAcceptsKeyValue(['a', 'b'], $value); + $this->assertAcceptsKeyValue(['a' => 'b'], $value); + } + } + + public function testAcceptsObjectKeys() + { + foreach ($this->getPossibleValues() as $value) { + $this->assertAcceptsKeyValue(new \stdClass(), $value); + $this->assertAcceptsKeyValue(new MixedStore(), $value); + $this->assertAcceptsKeyValue(function() {}, $value); + } + } + + private function assertAcceptsKeyValue($key, $value) + { + $err = 'Failed assertion that MixedStore accepts key ' . + Utils::printSafe($key) . ' with value ' . Utils::printSafe($value); + + $this->assertFalse($this->mixedStore->offsetExists($key), $err); + $this->mixedStore->offsetSet($key, $value); + $this->assertTrue($this->mixedStore->offsetExists($key), $err); + $this->assertSame($value, $this->mixedStore->offsetGet($key), $err); + $this->mixedStore->offsetUnset($key); + $this->assertFalse($this->mixedStore->offsetExists($key), $err); + $this->assertProvidesArrayAccess($key, $value); + } + + private function assertProvidesArrayAccess($key, $value) + { + $err = 'Failed assertion that MixedStore provides array access for key ' . + Utils::printSafe($key) . ' with value ' . Utils::printSafe($value); + + $this->assertFalse(isset($this->mixedStore[$key]), $err); + $this->mixedStore[$key] = $value; + $this->assertTrue(isset($this->mixedStore[$key]), $err); + $this->assertEquals(!empty($value), !empty($this->mixedStore[$key]), $err); + $this->assertSame($value, $this->mixedStore[$key], $err); + unset($this->mixedStore[$key]); + $this->assertFalse(isset($this->mixedStore[$key]), $err); + } +}