diff --git a/.gitignore b/.gitignore index c935546b..f3904c4c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ vendor/ data/schema.graphql composer.lock .idea +docker-compose.yml +Dockerfile +docker/ +.env.local \ No newline at end of file diff --git a/composer.json b/composer.json index 83fdde7d..a97635d3 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "youshido/graphql", - "description": "Pure PHP GraphQL", + "description": "Pure PHP 8.1+ GraphQL", "license": "MIT", "authors": [ { @@ -10,15 +10,19 @@ { "name": "Portey Vasil", "email": "portey@gmail.com" + }, + { + "name": "Tom Atom", + "email": "tom@tomatom.com" } ], "require": { - "php": ">=5.5", - "ext-mbstring": "*", - "symfony/property-access": "^2.8 || ^3.4 || ^4.4" + "php": ">=8.1", + "symfony/property-access": "6.4.* || 7.4.*", + "ext-mbstring": "*" }, "require-dev": { - "phpunit/phpunit": "^4.8" + "phpunit/phpunit": "^10" }, "autoload": { "psr-4": { @@ -30,4 +34,4 @@ "Youshido\\Tests\\": "tests" } } -} +} \ No newline at end of file diff --git a/examples/02_blog/Schema/BannerType.php b/examples/02_blog/Schema/BannerType.php index a2b5db57..7d4c0bdb 100644 --- a/examples/02_blog/Schema/BannerType.php +++ b/examples/02_blog/Schema/BannerType.php @@ -5,13 +5,14 @@ namespace Examples\Blog\Schema; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Scalar\StringType; class BannerType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config) { $config ->addField('title', new NonNullType(new StringType())) @@ -19,7 +20,7 @@ public function build($config) ->addField('imageLink', new StringType()); } - public function getInterfaces() + public function getInterfaces(): array { return [new ContentBlockInterface()]; } diff --git a/examples/02_blog/Schema/ContentBlockInterface.php b/examples/02_blog/Schema/ContentBlockInterface.php index 7f62f6df..344c4223 100644 --- a/examples/02_blog/Schema/ContentBlockInterface.php +++ b/examples/02_blog/Schema/ContentBlockInterface.php @@ -6,6 +6,7 @@ namespace Examples\Blog\Schema; +use Youshido\GraphQL\Config\Object\InterfaceTypeConfig; use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Scalar\StringType; @@ -13,7 +14,7 @@ class ContentBlockInterface extends AbstractInterfaceType { - public function build($config) + public function build(InterfaceTypeConfig $config) { $config->addField('title', new NonNullType(new StringType())); $config->addField('summary', new StringType()); diff --git a/examples/02_blog/Schema/ContentBlockUnion.php b/examples/02_blog/Schema/ContentBlockUnion.php index 17d4ba16..c0901991 100644 --- a/examples/02_blog/Schema/ContentBlockUnion.php +++ b/examples/02_blog/Schema/ContentBlockUnion.php @@ -6,16 +6,17 @@ namespace Examples\Blog\Schema; +use Youshido\GraphQL\Type\AbstractType; use Youshido\GraphQL\Type\Union\AbstractUnionType; class ContentBlockUnion extends AbstractUnionType { - public function getTypes() + public function getTypes(): array { return [new PostType(), new BannerType()]; } - public function resolveType($object) + public function resolveType(object $object): ?AbstractType { return empty($object['id']) ? null : (strpos($object['id'], 'post') !== false ? new PostType() : new BannerType()); } diff --git a/examples/02_blog/Schema/LikePostField.php b/examples/02_blog/Schema/LikePostField.php index bf795fa4..d2d9d775 100644 --- a/examples/02_blog/Schema/LikePostField.php +++ b/examples/02_blog/Schema/LikePostField.php @@ -31,7 +31,7 @@ public function getType() return new PostType(); } - public function build(FieldConfig $config) + public function build(FieldConfig $config): void { $config->addArgument('id', new NonNullType(new IntType())); } diff --git a/examples/02_blog/Schema/PostStatus.php b/examples/02_blog/Schema/PostStatus.php index b9f22aec..9450c7c4 100644 --- a/examples/02_blog/Schema/PostStatus.php +++ b/examples/02_blog/Schema/PostStatus.php @@ -10,7 +10,7 @@ class PostStatus extends AbstractEnumType { - public function getValues() + public function getValues(): array { return [ [ diff --git a/examples/02_blog/Schema/PostType.php b/examples/02_blog/Schema/PostType.php index 030cf72b..7f20daf8 100644 --- a/examples/02_blog/Schema/PostType.php +++ b/examples/02_blog/Schema/PostType.php @@ -5,6 +5,7 @@ namespace Examples\Blog\Schema; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Scalar\BooleanType; @@ -14,10 +15,10 @@ class PostType extends AbstractObjectType { /** - * @param \Youshido\GraphQL\Config\Object\ObjectTypeConfig $config + * @param ObjectTypeConfig $config * @throws \Youshido\GraphQL\Exception\ConfigurationException */ - public function build($config) + public function build(ObjectTypeConfig $config) { $config ->addField('oldTitle', [ @@ -49,7 +50,7 @@ public function getOne($id) return DataProvider::getPost($id); } - public function getInterfaces() + public function getInterfaces(): array { return [new ContentBlockInterface()]; } diff --git a/examples/03_relay_star_wars/Schema/FactionType.php b/examples/03_relay_star_wars/Schema/FactionType.php index 77e0ec6f..72e04c9e 100644 --- a/examples/03_relay_star_wars/Schema/FactionType.php +++ b/examples/03_relay_star_wars/Schema/FactionType.php @@ -9,6 +9,7 @@ namespace Examples\StarWars; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Relay\Connection\ArrayConnection; use Youshido\GraphQL\Relay\Connection\Connection; use Youshido\GraphQL\Relay\Field\GlobalIdField; @@ -22,7 +23,7 @@ class FactionType extends AbstractObjectType const TYPE_KEY = 'faction'; - public function build($config) + public function build(ObjectTypeConfig $config) { $config ->addField(new GlobalIdField(self::TYPE_KEY)) @@ -49,7 +50,7 @@ public function build($config) } - public function getDescription() + public function getDescription(): string { return 'A faction in the Star Wars saga'; } @@ -59,7 +60,7 @@ public function getOne($id) return TestDataProvider::getFaction($id); } - public function getInterfaces() + public function getInterfaces(): array { return [new NodeInterfaceType()]; } diff --git a/examples/03_relay_star_wars/Schema/ShipType.php b/examples/03_relay_star_wars/Schema/ShipType.php index f43de101..dbc2777c 100644 --- a/examples/03_relay_star_wars/Schema/ShipType.php +++ b/examples/03_relay_star_wars/Schema/ShipType.php @@ -9,6 +9,7 @@ namespace Examples\StarWars; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Relay\Field\GlobalIdField; use Youshido\GraphQL\Relay\NodeInterfaceType; use Youshido\GraphQL\Type\Object\AbstractObjectType; @@ -18,7 +19,7 @@ class ShipType extends AbstractObjectType { const TYPE_KEY = 'ship'; - public function build($config) + public function build(ObjectTypeConfig $config) { $config ->addField(new GlobalIdField(self::TYPE_KEY)) @@ -30,12 +31,12 @@ public function getOne($id) return TestDataProvider::getShip($id); } - public function getDescription() + public function getDescription(): string { return 'A ship in the Star Wars saga'; } - public function getInterfaces() + public function getInterfaces(): array { return [new NodeInterfaceType()]; } diff --git a/examples/03_relay_star_wars/Schema/StarWarsRelaySchema.php b/examples/03_relay_star_wars/Schema/StarWarsRelaySchema.php index af73ae78..76293a0a 100644 --- a/examples/03_relay_star_wars/Schema/StarWarsRelaySchema.php +++ b/examples/03_relay_star_wars/Schema/StarWarsRelaySchema.php @@ -3,6 +3,7 @@ namespace Examples\StarWars; use Youshido\GraphQL\Config\Schema\SchemaConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Field\InputField; use Youshido\GraphQl\Relay\Connection\ArrayConnection; use Youshido\GraphQL\Relay\Connection\Connection; @@ -16,20 +17,19 @@ class StarWarsRelaySchema extends AbstractSchema { - public function build(SchemaConfig $config) + /** + * @throws ConfigurationException + */ + public function build(SchemaConfig $config): void { $fetcher = new CallableFetcher( function ($type, $id) { - switch ($type) { - case FactionType::TYPE_KEY: - return TestDataProvider::getFaction($id); + return match ($type) { + FactionType::TYPE_KEY => TestDataProvider::getFaction($id), + ShipType::TYPE_KEY => TestDataProvider::getShip($id), + default => null, + }; - case - ShipType::TYPE_KEY: - return TestDataProvider::getShip($id); - } - - return null; }, function ($object) { return $object && array_key_exists('ships', $object) ? new FactionType() : new ShipType(); @@ -57,7 +57,7 @@ function ($object) { 'type' => new ListType(new StringType()) ] ], - 'resolve' => function ($value = null, $args, $info) { + 'resolve' => function ($args, $info, $value = null) { return TestDataProvider::getByNames($args['names']); } ]); diff --git a/examples/04_bookstore/Schema/Type/AuthorType.php b/examples/04_bookstore/Schema/Type/AuthorType.php index ed377d86..983405b9 100644 --- a/examples/04_bookstore/Schema/Type/AuthorType.php +++ b/examples/04_bookstore/Schema/Type/AuthorType.php @@ -8,6 +8,7 @@ namespace Examples\BookStore\Schema\Type; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Scalar\IdType; @@ -15,7 +16,7 @@ class AuthorType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config) { $config->addFields([ 'id' => new NonNullType(new IdType()), diff --git a/examples/04_bookstore/Schema/Type/BookType.php b/examples/04_bookstore/Schema/Type/BookType.php index 80991d55..3eba22fc 100644 --- a/examples/04_bookstore/Schema/Type/BookType.php +++ b/examples/04_bookstore/Schema/Type/BookType.php @@ -17,7 +17,7 @@ class BookType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config) { $config->addFields([ 'id' => new IdType(), diff --git a/examples/04_bookstore/Schema/Type/CategoryType.php b/examples/04_bookstore/Schema/Type/CategoryType.php index c24da239..ed0e39ef 100644 --- a/examples/04_bookstore/Schema/Type/CategoryType.php +++ b/examples/04_bookstore/Schema/Type/CategoryType.php @@ -9,6 +9,7 @@ namespace Examples\BookStore\Schema\Type; use Examples\BookStore\Schema\Field\CategoriesField; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\ListType\ListType; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Scalar\IdType; @@ -16,7 +17,7 @@ class CategoryType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config) { $config->addFields([ 'id' => new IdType(), diff --git a/src/Config/AbstractConfig.php b/src/Config/AbstractConfig.php index 55b3bf1d..67980dc3 100644 --- a/src/Config/AbstractConfig.php +++ b/src/Config/AbstractConfig.php @@ -9,8 +9,8 @@ namespace Youshido\GraphQL\Config; +use Exception; use Youshido\GraphQL\Exception\ConfigurationException; -use Youshido\GraphQL\Exception\ValidationException; use Youshido\GraphQL\Validator\ConfigValidator\ConfigValidator; /** @@ -20,42 +20,38 @@ */ abstract class AbstractConfig { + protected array $data; - /** - * @var array - */ - protected $data = []; + protected mixed $contextObject; - protected $contextObject; + protected bool $finalClass = false; - protected $finalClass = false; - - protected $extraFieldsAllowed = null; + protected bool $extraFieldsAllowed = false; /** * TypeConfig constructor. * - * @param array $configData - * @param mixed $contextObject - * @param bool $finalClass + * @param mixed|null $contextObject * * @throws ConfigurationException - * @throws ValidationException */ - public function __construct(array $configData, $contextObject = null, $finalClass = false) + public function __construct(array $configData, mixed $contextObject = null, bool $finalClass = false) { - if (empty($configData)) { + if ($configData === []) { throw new ConfigurationException('Config for Type should be an array'); } $this->contextObject = $contextObject; - $this->data = $configData; - $this->finalClass = $finalClass; + $this->data = $configData; + $this->finalClass = $finalClass; $this->build(); } - public function validate() + /** + * @throws ConfigurationException + */ + public function validate(): void { $validator = ConfigValidator::getInstance(); @@ -64,7 +60,7 @@ public function validate() } } - public function getContextRules() + public function getContextRules(): array { $rules = $this->getRules(); if ($this->finalClass) { @@ -90,7 +86,7 @@ public function getType() return $this->get('type'); } - public function getData() + public function getData(): array { return $this->data; } @@ -100,23 +96,19 @@ public function getContextObject() return $this->contextObject; } - public function isFinalClass() + public function isFinalClass(): bool { return $this->finalClass; } - public function isExtraFieldsAllowed() + public function isExtraFieldsAllowed(): bool { return $this->extraFieldsAllowed; } - - /** - * @return null|callable - */ - public function getResolveFunction() + public function getResolveFunction(): ?callable { - return $this->get('resolve', null); + return $this->get('resolve'); } protected function build() @@ -125,44 +117,44 @@ protected function build() /** * @param $key - * @param null $defaultValue * * @return mixed|null|callable */ - public function get($key, $defaultValue = null) + public function get($key, $defaultValue = null): mixed { return $this->has($key) ? $this->data[$key] : $defaultValue; } - public function set($key, $value) + public function set($key, $value): static { $this->data[$key] = $value; return $this; } - public function has($key) + public function has($key): bool { return array_key_exists($key, $this->data); } - public function __call($method, $arguments) + /** + * @throws Exception + */ + public function __call(string $method, array $arguments) { - if (substr($method, 0, 3) == 'get') { + if (str_starts_with($method, 'get')) { $propertyName = lcfirst(substr($method, 3)); - } elseif (substr($method, 0, 3) == 'set') { + } elseif (str_starts_with($method, 'set')) { $propertyName = lcfirst(substr($method, 3)); $this->set($propertyName, $arguments[0]); return $this; - } elseif (substr($method, 0, 2) == 'is') { + } elseif (str_starts_with($method, 'is')) { $propertyName = lcfirst(substr($method, 2)); } else { - throw new \Exception('Call to undefined method ' . $method); + throw new Exception('Call to undefined method ' . $method); } return $this->get($propertyName); } - - -} +} \ No newline at end of file diff --git a/src/Config/Directive/DirectiveConfig.php b/src/Config/Directive/DirectiveConfig.php index 2a148d83..e67ad919 100644 --- a/src/Config/Directive/DirectiveConfig.php +++ b/src/Config/Directive/DirectiveConfig.php @@ -24,13 +24,13 @@ class DirectiveConfig extends AbstractConfig protected $locations = []; - public function getRules() + public function getRules(): array { return [ - 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], + 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], 'description' => ['type' => TypeService::TYPE_STRING], - 'args' => ['type' => TypeService::TYPE_ARRAY], - 'locations' => ['type' => TypeService::TYPE_ARRAY], + 'args' => ['type' => TypeService::TYPE_ARRAY], + 'locations' => ['type' => TypeService::TYPE_ARRAY], ]; } @@ -39,7 +39,7 @@ public function getLocations() return $this->locations; } - public function build() + protected function build() { $this->buildArguments(); diff --git a/src/Config/Field/FieldConfig.php b/src/Config/Field/FieldConfig.php index f1058730..ba946995 100644 --- a/src/Config/Field/FieldConfig.php +++ b/src/Config/Field/FieldConfig.php @@ -25,17 +25,17 @@ class FieldConfig extends AbstractConfig use ArgumentsAwareConfigTrait; - public function getRules() + public function getRules(): array { return [ - 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], - 'type' => ['type' => TypeService::TYPE_GRAPHQL_TYPE, 'final' => true], - 'args' => ['type' => TypeService::TYPE_ARRAY], - 'description' => ['type' => TypeService::TYPE_STRING], - 'resolve' => ['type' => TypeService::TYPE_CALLABLE], - 'isDeprecated' => ['type' => TypeService::TYPE_BOOLEAN], + 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], + 'type' => ['type' => TypeService::TYPE_GRAPHQL_TYPE, 'final' => true], + 'args' => ['type' => TypeService::TYPE_ARRAY], + 'description' => ['type' => TypeService::TYPE_STRING], + 'resolve' => ['type' => TypeService::TYPE_CALLABLE], + 'isDeprecated' => ['type' => TypeService::TYPE_BOOLEAN], 'deprecationReason' => ['type' => TypeService::TYPE_STRING], - 'cost' => ['type' => TypeService::TYPE_ANY] + 'cost' => ['type' => TypeService::TYPE_ANY] ]; } diff --git a/src/Config/Field/InputFieldConfig.php b/src/Config/Field/InputFieldConfig.php index e0300698..846a3aa7 100644 --- a/src/Config/Field/InputFieldConfig.php +++ b/src/Config/Field/InputFieldConfig.php @@ -20,19 +20,19 @@ class InputFieldConfig extends AbstractConfig { - public function getRules() + public function getRules(): array { return [ - 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], - 'type' => ['type' => TypeService::TYPE_ANY_INPUT, 'final' => true], - 'defaultValue' => ['type' => TypeService::TYPE_ANY], - 'description' => ['type' => TypeService::TYPE_STRING], - 'isDeprecated' => ['type' => TypeService::TYPE_BOOLEAN], + 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], + 'type' => ['type' => TypeService::TYPE_ANY_INPUT, 'final' => true], + 'defaultValue' => ['type' => TypeService::TYPE_ANY], + 'description' => ['type' => TypeService::TYPE_STRING], + 'isDeprecated' => ['type' => TypeService::TYPE_BOOLEAN], 'deprecationReason' => ['type' => TypeService::TYPE_STRING], ]; } - public function getDefaultValue() + public function getDefaultValue(): mixed { return $this->get('defaultValue'); } diff --git a/src/Config/Object/EnumTypeConfig.php b/src/Config/Object/EnumTypeConfig.php index b7ea9b49..a8ce0d67 100644 --- a/src/Config/Object/EnumTypeConfig.php +++ b/src/Config/Object/EnumTypeConfig.php @@ -17,18 +17,19 @@ class EnumTypeConfig extends AbstractConfig implements TypeConfigInterface { - use FieldsAwareConfigTrait, ArgumentsAwareConfigTrait; + use FieldsAwareConfigTrait; + use ArgumentsAwareConfigTrait; - public function getRules() + public function getRules(): array { return [ - 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], + 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], 'description' => ['type' => TypeService::TYPE_STRING], - 'values' => ['type' => TypeService::TYPE_ENUM_VALUES, 'required' => true], + 'values' => ['type' => TypeService::TYPE_ENUM_VALUES, 'required' => true], ]; } - public function getValues() + public function getValues(): mixed { return $this->get('values', []); } diff --git a/src/Config/Object/InputObjectTypeConfig.php b/src/Config/Object/InputObjectTypeConfig.php index 2d2b2e0d..d2252b8d 100644 --- a/src/Config/Object/InputObjectTypeConfig.php +++ b/src/Config/Object/InputObjectTypeConfig.php @@ -13,11 +13,11 @@ class InputObjectTypeConfig extends ObjectTypeConfig { - public function getRules() + public function getRules(): array { return [ - 'name' => ['type' => TypeService::TYPE_STRING, 'required' => true], - 'fields' => ['type' => TypeService::TYPE_ARRAY_OF_INPUT_FIELDS, 'final' => true], + 'name' => ['type' => TypeService::TYPE_STRING, 'required' => true], + 'fields' => ['type' => TypeService::TYPE_ARRAY_OF_INPUT_FIELDS, 'final' => true], 'description' => ['type' => TypeService::TYPE_STRING], ]; } diff --git a/src/Config/Object/InterfaceTypeConfig.php b/src/Config/Object/InterfaceTypeConfig.php index 01a27118..86fcecff 100644 --- a/src/Config/Object/InterfaceTypeConfig.php +++ b/src/Config/Object/InterfaceTypeConfig.php @@ -23,23 +23,30 @@ */ class InterfaceTypeConfig extends AbstractConfig implements TypeConfigInterface { - use FieldsAwareConfigTrait, ArgumentsAwareConfigTrait; + use FieldsAwareConfigTrait; + use ArgumentsAwareConfigTrait; - public function getRules() + public function getRules(): array { return [ - 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], - 'fields' => ['type' => TypeService::TYPE_ARRAY_OF_FIELDS_CONFIG, 'final' => true], + 'name' => ['type' => TypeService::TYPE_STRING, 'final' => true], + 'fields' => ['type' => TypeService::TYPE_ARRAY_OF_FIELDS_CONFIG, 'final' => true], 'description' => ['type' => TypeService::TYPE_STRING], 'resolveType' => ['type' => TypeService::TYPE_CALLABLE, 'final' => true], ]; } + /** + * @throws ConfigurationException + */ protected function build() { $this->buildFields(); } + /** + * @throws ConfigurationException + */ public function resolveType($object) { $callable = $this->get('resolveType'); diff --git a/src/Config/Object/ListTypeConfig.php b/src/Config/Object/ListTypeConfig.php index 02a82b09..82dd6c7f 100644 --- a/src/Config/Object/ListTypeConfig.php +++ b/src/Config/Object/ListTypeConfig.php @@ -13,12 +13,12 @@ class ListTypeConfig extends ObjectTypeConfig { - public function getRules() + public function getRules(): array { return [ 'itemType' => ['type' => TypeService::TYPE_GRAPHQL_TYPE, 'final' => true], - 'resolve' => ['type' => TypeService::TYPE_CALLABLE], - 'args' => ['type' => TypeService::TYPE_ARRAY_OF_INPUT_FIELDS], + 'resolve' => ['type' => TypeService::TYPE_CALLABLE], + 'args' => ['type' => TypeService::TYPE_ARRAY_OF_INPUT_FIELDS], ]; } diff --git a/src/Config/Object/ObjectTypeConfig.php b/src/Config/Object/ObjectTypeConfig.php index 76c57cdd..eea6e633 100644 --- a/src/Config/Object/ObjectTypeConfig.php +++ b/src/Config/Object/ObjectTypeConfig.php @@ -11,6 +11,7 @@ use Youshido\GraphQL\Config\AbstractConfig; use Youshido\GraphQL\Config\Traits\FieldsAwareConfigTrait; use Youshido\GraphQL\Config\TypeConfigInterface; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType; use Youshido\GraphQL\Type\TypeService; @@ -25,17 +26,20 @@ class ObjectTypeConfig extends AbstractConfig implements TypeConfigInterface use FieldsAwareConfigTrait; - public function getRules() + public function getRules(): array { return [ - 'name' => ['type' => TypeService::TYPE_STRING, 'required' => true], + 'name' => ['type' => TypeService::TYPE_STRING, 'required' => true], 'description' => ['type' => TypeService::TYPE_STRING], - 'fields' => ['type' => TypeService::TYPE_ARRAY_OF_FIELDS_CONFIG, 'final' => true], - 'interfaces' => ['type' => TypeService::TYPE_ARRAY_OF_INTERFACES] + 'fields' => ['type' => TypeService::TYPE_ARRAY_OF_FIELDS_CONFIG, 'final' => true], + 'interfaces' => ['type' => TypeService::TYPE_ARRAY_OF_INTERFACES] ]; } - protected function build() + /** + * @throws ConfigurationException + */ + protected function build(): void { $this->buildFields(); } @@ -43,9 +47,8 @@ protected function build() /** * @return AbstractInterfaceType[] */ - public function getInterfaces() + public function getInterfaces(): array { return $this->get('interfaces', []); } - -} +} \ No newline at end of file diff --git a/src/Config/Object/UnionTypeConfig.php b/src/Config/Object/UnionTypeConfig.php index 35611cdd..ad9d3059 100644 --- a/src/Config/Object/UnionTypeConfig.php +++ b/src/Config/Object/UnionTypeConfig.php @@ -17,13 +17,14 @@ class UnionTypeConfig extends AbstractConfig implements TypeConfigInterface { - use FieldsAwareConfigTrait, ArgumentsAwareConfigTrait; + use FieldsAwareConfigTrait; + use ArgumentsAwareConfigTrait; - public function getRules() + public function getRules(): array { return [ - 'name' => ['type' => TypeService::TYPE_STRING, 'required' => true], - 'types' => ['type' => TypeService::TYPE_ARRAY_OF_OBJECT_TYPES], + 'name' => ['type' => TypeService::TYPE_STRING, 'required' => true], + 'types' => ['type' => TypeService::TYPE_ARRAY_OF_OBJECT_TYPES], 'description' => ['type' => TypeService::TYPE_STRING], 'resolveType' => ['type' => TypeService::TYPE_CALLABLE, 'final' => true] ]; diff --git a/src/Config/Schema/SchemaConfig.php b/src/Config/Schema/SchemaConfig.php index a34ad27b..65a4b65f 100644 --- a/src/Config/Schema/SchemaConfig.php +++ b/src/Config/Schema/SchemaConfig.php @@ -19,16 +19,14 @@ class SchemaConfig extends AbstractConfig { - /** - * @var SchemaTypesList - */ - private $typesList; + private readonly SchemaTypesList $typesList; + /** * @var SchemaDirectivesList; */ - private $directiveList; + private readonly SchemaDirectivesList $directiveList; - public function __construct(array $configData, $contextObject = null, $finalClass = false) + public function __construct(array $configData, mixed $contextObject = null, bool $finalClass = false) { $this->typesList = new SchemaTypesList(); $this->directiveList = new SchemaDirectivesList(); @@ -36,14 +34,14 @@ public function __construct(array $configData, $contextObject = null, $finalClas } - public function getRules() + public function getRules(): array { return [ - 'query' => ['type' => TypeService::TYPE_OBJECT_TYPE, 'required' => true], - 'mutation' => ['type' => TypeService::TYPE_OBJECT_TYPE], - 'types' => ['type' => TypeService::TYPE_ARRAY], + 'query' => ['type' => TypeService::TYPE_OBJECT_TYPE, 'required' => true], + 'mutation' => ['type' => TypeService::TYPE_OBJECT_TYPE], + 'types' => ['type' => TypeService::TYPE_ARRAY], 'directives' => ['type' => TypeService::TYPE_ARRAY], - 'name' => ['type' => TypeService::TYPE_STRING], + 'name' => ['type' => TypeService::TYPE_STRING], ]; } @@ -53,6 +51,7 @@ protected function build() if (!empty($this->data['types'])) { $this->typesList->addTypes($this->data['types']); } + if (!empty($this->data['directives'])) { $this->directiveList->addDirectives($this->data['directives']); } @@ -69,10 +68,8 @@ public function getQuery() /** * @param $query AbstractObjectType - * - * @return SchemaConfig */ - public function setQuery($query) + public function setQuery($query): static { $this->data['query'] = $query; @@ -82,34 +79,32 @@ public function setQuery($query) /** * @return ObjectType */ - public function getMutation() + public function getMutation(): mixed { return $this->get('mutation'); } /** * @param $query AbstractObjectType - * - * @return SchemaConfig */ - public function setMutation($query) + public function setMutation($query): static { $this->data['mutation'] = $query; return $this; } - public function getName() + public function getName(): mixed { return $this->get('name', 'RootSchema'); } - public function getTypesList() + public function getTypesList(): SchemaTypesList { return $this->typesList; } - public function getDirectiveList() + public function getDirectiveList(): SchemaDirectivesList { return $this->directiveList; } diff --git a/src/Config/Traits/ArgumentsAwareConfigTrait.php b/src/Config/Traits/ArgumentsAwareConfigTrait.php index 67703b95..8f16891d 100644 --- a/src/Config/Traits/ArgumentsAwareConfigTrait.php +++ b/src/Config/Traits/ArgumentsAwareConfigTrait.php @@ -9,14 +9,16 @@ namespace Youshido\GraphQL\Config\Traits; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Field\InputField; trait ArgumentsAwareConfigTrait { - protected $arguments = []; + protected array $arguments = []; + protected $_isArgumentsBuilt; - public function buildArguments() + public function buildArguments(): void { if ($this->_isArgumentsBuilt) { return; @@ -25,15 +27,15 @@ public function buildArguments() if (!empty($this->data['args'])) { $this->addArguments($this->data['args']); } + $this->_isArgumentsBuilt = true; } - public function addArguments($argsList) + public function addArguments($argsList): static { foreach ($argsList as $argumentName => $argumentInfo) { if ($argumentInfo instanceof InputField) { $this->arguments[$argumentInfo->getName()] = $argumentInfo; - continue; } else { $this->addArgument($argumentName, $this->buildConfig($argumentName, $argumentInfo)); } @@ -42,17 +44,21 @@ public function addArguments($argsList) return $this; } - public function addArgument($argument, $argumentInfo = null) + /** + * @throws ConfigurationException + */ + public function addArgument($argument, $argumentInfo = null): static { if (!($argument instanceof InputField)) { $argument = new InputField($this->buildConfig($argument, $argumentInfo)); } + $this->arguments[$argument->getName()] = $argument; return $this; } - protected function buildConfig($name, $info = null) + protected function buildConfig($name, $info = null): array { if (!is_array($info)) { return [ @@ -60,6 +66,7 @@ protected function buildConfig($name, $info = null) 'name' => $name ]; } + if (empty($info['name'])) { $info['name'] = $name; } @@ -69,25 +76,21 @@ protected function buildConfig($name, $info = null) /** * @param $name - * - * @return InputField */ - public function getArgument($name) + public function getArgument($name): ?InputField { return $this->hasArgument($name) ? $this->arguments[$name] : null; } /** * @param $name - * - * @return bool */ - public function hasArgument($name) + public function hasArgument($name): bool { return array_key_exists($name, $this->arguments); } - public function hasArguments() + public function hasArguments(): bool { return !empty($this->arguments); } @@ -95,12 +98,12 @@ public function hasArguments() /** * @return InputField[] */ - public function getArguments() + public function getArguments(): array { return $this->arguments; } - public function removeArgument($name) + public function removeArgument($name): static { if ($this->hasArgument($name)) { unset($this->arguments[$name]); diff --git a/src/Config/Traits/ConfigAwareTrait.php b/src/Config/Traits/ConfigAwareTrait.php index a3b91305..04e34bdc 100644 --- a/src/Config/Traits/ConfigAwareTrait.php +++ b/src/Config/Traits/ConfigAwareTrait.php @@ -19,9 +19,10 @@ trait ConfigAwareTrait /** @var AbstractConfig|ObjectTypeConfig|FieldConfig|InputFieldConfig */ protected $config; + protected $configCache = []; - public function getConfig() + public function getConfig(): AbstractConfig|ObjectTypeConfig|FieldConfig|InputFieldConfig { return $this->config; } @@ -31,13 +32,13 @@ protected function getConfigValue($key, $defaultValue = null) if (array_key_exists($key, $this->configCache)) { return $this->configCache[$key]; } - $this->configCache[$key] = !empty($this->config) ? $this->config->get($key, $defaultValue) : $defaultValue; + + $this->configCache[$key] = empty($this->config) ? $defaultValue : $this->config->get($key, $defaultValue); return $this->configCache[$key]; } - public function getDescription() + public function getDescription(): string { return $this->getConfigValue('description'); } - -} +} \ No newline at end of file diff --git a/src/Config/Traits/DirectivesAwareConfigTrait.php b/src/Config/Traits/DirectivesAwareConfigTrait.php index 1b7632b9..43e3963d 100644 --- a/src/Config/Traits/DirectivesAwareConfigTrait.php +++ b/src/Config/Traits/DirectivesAwareConfigTrait.php @@ -13,10 +13,11 @@ trait DirectivesAwareConfigTrait { - protected $directives = []; - protected $_isDirectivesBuilt; + protected array $directives = []; - public function buildDirectives() + protected ?bool $_isDirectivesBuilt; + + public function buildDirectives(): void { if ($this->_isDirectivesBuilt) { return; @@ -25,15 +26,15 @@ public function buildDirectives() if (!empty($this->data['directives'])) { $this->addDirectives($this->data['directives']); } + $this->_isDirectivesBuilt = true; } - public function addDirectives($directiveList) + public function addDirectives($directiveList): static { foreach ($directiveList as $directiveName => $directiveInfo) { if ($directiveInfo instanceof Directive) { $this->directives[$directiveInfo->getName()] = $directiveInfo; - continue; } else { $this->addDirective($directiveName, $this->buildConfig($directiveName, $directiveInfo)); } @@ -42,11 +43,12 @@ public function addDirectives($directiveList) return $this; } - public function addDirective($directive, $directiveInfo = null) + public function addDirective($directive, $directiveInfo = null): static { if (!($directive instanceof Directive)) { $directive = new Directive($this->buildConfig($directive, $directiveInfo)); } + $this->directives[$directive->getName()] = $directive; return $this; @@ -57,22 +59,20 @@ public function addDirective($directive, $directiveInfo = null) * * @return InputField */ - public function getDirective($name) + public function getDirective($name): ?InputField { return $this->hasDirective($name) ? $this->directives[$name] : null; } /** * @param $name - * - * @return bool */ - public function hasDirective($name) + public function hasDirective($name): bool { return array_key_exists($name, $this->directives); } - public function hasDirectives() + public function hasDirectives(): bool { return !empty($this->directives); } @@ -80,12 +80,12 @@ public function hasDirectives() /** * @return InputField[] */ - public function getDirectives() + public function getDirectives(): array { return $this->directives; } - public function removeDirective($name) + public function removeDirective($name): static { if ($this->hasDirective($name)) { unset($this->directives[$name]); @@ -94,4 +94,19 @@ public function removeDirective($name) return $this; } + protected function buildConfig($name, $info = null): array + { + if (!is_array($info)) { + return [ + 'type' => $info, + 'name' => $name + ]; + } + + if (empty($info['name'])) { + $info['name'] = $name; + } + + return $info; + } } diff --git a/src/Config/Traits/FieldsAwareConfigTrait.php b/src/Config/Traits/FieldsAwareConfigTrait.php index f6d360ff..18f30c60 100644 --- a/src/Config/Traits/FieldsAwareConfigTrait.php +++ b/src/Config/Traits/FieldsAwareConfigTrait.php @@ -10,7 +10,6 @@ use Youshido\GraphQL\Exception\ConfigurationException; -use Youshido\GraphQL\Exception\ValidationException; use Youshido\GraphQL\Field\Field; use Youshido\GraphQL\Field\FieldInterface; use Youshido\GraphQL\Field\InputFieldInterface; @@ -22,9 +21,12 @@ */ trait FieldsAwareConfigTrait { - protected $fields = []; + protected array $fields = []; - public function buildFields() + /** + * @throws ConfigurationException + */ + public function buildFields(): void { if (!empty($this->data['fields'])) { $this->addFields($this->data['fields']); @@ -33,10 +35,11 @@ public function buildFields() /** * Add fields from passed interface - * @param AbstractInterfaceType $interfaceType * @return $this + * @throws ConfigurationException + * @throws ConfigurationException */ - public function applyInterface(AbstractInterfaceType $interfaceType) + public function applyInterface(AbstractInterfaceType $interfaceType): static { $this->addFields($interfaceType->getFields()); @@ -44,19 +47,17 @@ public function applyInterface(AbstractInterfaceType $interfaceType) } /** - * @param array $fieldsList * @return $this + * @throws ConfigurationException */ - public function addFields($fieldsList) + public function addFields(array $fieldsList): static { foreach ($fieldsList as $fieldName => $fieldConfig) { if ($fieldConfig instanceof FieldInterface) { $this->fields[$fieldConfig->getName()] = $fieldConfig; - continue; - } elseif($fieldConfig instanceof InputFieldInterface) { + } elseif ($fieldConfig instanceof InputFieldInterface) { $this->fields[$fieldConfig->getName()] = $fieldConfig; - continue; } else { $this->addField($fieldName, $this->buildFieldConfig($fieldName, $fieldConfig)); } @@ -66,14 +67,14 @@ public function addFields($fieldsList) } /** - * @param FieldInterface|string $field Field name or Field Object - * @param mixed $fieldInfo Field Type or Field Config array + * @param mixed $field Field name or Field Object + * @param null $fieldInfo Field Type or Field Config array * * @return $this * * @throws ConfigurationException */ - public function addField($field, $fieldInfo = null) + public function addField(mixed $field, $fieldInfo = null): static { if (!($field instanceof FieldInterface)) { $field = new Field($this->buildFieldConfig($field, $fieldInfo)); @@ -82,7 +83,7 @@ public function addField($field, $fieldInfo = null) if ($this->hasField($field->getName())) { throw new ConfigurationException(sprintf('Type "%s" was defined more than once', $field->getName())); } - + $this->fields[$field->getName()] = $field; return $this; @@ -104,25 +105,21 @@ protected function buildFieldConfig($name, $info = null) /** * @param $name - * - * @return Field */ - public function getField($name) + public function getField($name): mixed { return $this->hasField($name) ? $this->fields[$name] : null; } /** * @param $name - * - * @return bool */ - public function hasField($name) + public function hasField($name): bool { return array_key_exists($name, $this->fields); } - public function hasFields() + public function hasFields(): bool { return !empty($this->fields); } @@ -130,12 +127,12 @@ public function hasFields() /** * @return Field[] */ - public function getFields() + public function getFields(): array { return $this->fields; } - public function removeField($name) + public function removeField($name): static { if ($this->hasField($name)) { unset($this->fields[$name]); @@ -143,4 +140,4 @@ public function removeField($name) return $this; } -} +} \ No newline at end of file diff --git a/src/Config/Traits/ResolvableObjectTrait.php b/src/Config/Traits/ResolvableObjectTrait.php index 55d8718a..2f1ab5bd 100644 --- a/src/Config/Traits/ResolvableObjectTrait.php +++ b/src/Config/Traits/ResolvableObjectTrait.php @@ -7,32 +7,33 @@ namespace Youshido\GraphQL\Config\Traits; +use Exception; use Youshido\GraphQL\Execution\ResolveInfo; use Youshido\GraphQL\Type\TypeMap; use Youshido\GraphQL\Type\TypeService; trait ResolvableObjectTrait { - - public function resolve($value, array $args, ResolveInfo $info) + /** + * @throws Exception + */ + public function resolve($value, array $args, ResolveInfo $info): mixed { if ($resolveFunction = $this->getConfig()->getResolveFunction()) { return $resolveFunction($value, $args, $info); + } elseif (is_array($value) && array_key_exists($this->getName(), $value)) { + return $value[$this->getName()]; + } elseif (is_object($value)) { + return TypeService::getPropertyValue($value, $this->getName()); + } elseif ($this->getType()->getKind() !== TypeMap::KIND_NON_NULL) { + return null; } else { - if (is_array($value) && array_key_exists($this->getName(), $value)) { - return $value[$this->getName()]; - } elseif (is_object($value)) { - return TypeService::getPropertyValue($value, $this->getName()); - } elseif ($this->getType()->getKind() !== TypeMap::KIND_NON_NULL) { - return null; - } else { - throw new \Exception(sprintf('Property "%s" not found in resolve result', $this->getName())); - } + throw new Exception(sprintf('Property "%s" not found in resolve result', $this->getName())); } } - public function getResolveFunction() + public function getResolveFunction(): ?callable { return $this->getConfig()->getResolveFunction(); } diff --git a/src/Config/TypeConfigInterface.php b/src/Config/TypeConfigInterface.php index 3312fe31..0ad1e32b 100644 --- a/src/Config/TypeConfigInterface.php +++ b/src/Config/TypeConfigInterface.php @@ -12,12 +12,7 @@ interface TypeConfigInterface { - - /** - * @param Field|string $field - * @param array $fieldInfo - */ - public function addField($field, $fieldInfo = null); + public function addField(Field|string $field, ?array $fieldInfo = null); public function getField($name); diff --git a/src/Directive/Directive.php b/src/Directive/Directive.php index 5a29569e..2c1b7274 100644 --- a/src/Directive/Directive.php +++ b/src/Directive/Directive.php @@ -8,6 +8,7 @@ namespace Youshido\GraphQL\Directive; use Youshido\GraphQL\Config\Directive\DirectiveConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\Traits\ArgumentsAwareObjectTrait; use Youshido\GraphQL\Type\Traits\AutoNameTrait; @@ -19,6 +20,9 @@ class Directive implements DirectiveInterface protected $isFinal = false; + /** + * @throws ConfigurationException + */ public function __construct(array $config = []) { if (empty($config['name'])) { @@ -29,7 +33,7 @@ public function __construct(array $config = []) $this->build($this->config); } - public function build(DirectiveConfig $config) + public function build(DirectiveConfig $config): void { } diff --git a/src/Directive/DirectiveInterface.php b/src/Directive/DirectiveInterface.php index d71b8c09..4821a730 100644 --- a/src/Directive/DirectiveInterface.php +++ b/src/Directive/DirectiveInterface.php @@ -24,25 +24,12 @@ public function addArgument($argument, $ArgumentInfo = null); /** * @return AbstractType[] */ - public function getArguments(); + public function getArguments(): array; - /** - * @param string $argumentName - * - * @return AbstractType - */ - public function getArgument($argumentName); + public function getArgument(string $argumentName); - /** - * @param string $argumentName - * - * @return bool - */ - public function hasArgument($argumentName); + public function hasArgument(string $argumentName): bool; - /** - * @return boolean - */ - public function hasArguments(); + public function hasArguments(): bool; } diff --git a/src/Directive/DirectiveLocation.php b/src/Directive/DirectiveLocation.php index 32a0e15d..d3a55875 100644 --- a/src/Directive/DirectiveLocation.php +++ b/src/Directive/DirectiveLocation.php @@ -11,12 +11,19 @@ class DirectiveLocation { - const QUERY = 'QUERY'; - const MUTATION = 'MUTATION'; - const FIELD = 'FIELD'; - const FIELD_DEFINITION = 'FIELD_DEFINITION'; - const FRAGMENT_DEFINITION = 'FRAGMENT_DEFINITION'; - const FRAGMENT_SPREAD = 'FRAGMENT_SPREAD'; - const INLINE_FRAGMENT = 'INLINE_FRAGMENT'; - const ENUM_VALUE = 'ENUM_VALUE'; + final const QUERY = 'QUERY'; + + final const MUTATION = 'MUTATION'; + + final const FIELD = 'FIELD'; + + final const FIELD_DEFINITION = 'FIELD_DEFINITION'; + + final const FRAGMENT_DEFINITION = 'FRAGMENT_DEFINITION'; + + final const FRAGMENT_SPREAD = 'FRAGMENT_SPREAD'; + + final const INLINE_FRAGMENT = 'INLINE_FRAGMENT'; + + final const ENUM_VALUE = 'ENUM_VALUE'; } diff --git a/src/Exception/ConfigurationException.php b/src/Exception/ConfigurationException.php index 021ae5c2..a9b6d2d2 100644 --- a/src/Exception/ConfigurationException.php +++ b/src/Exception/ConfigurationException.php @@ -9,7 +9,9 @@ namespace Youshido\GraphQL\Exception; -class ConfigurationException extends \Exception +use Exception; + +class ConfigurationException extends Exception { } \ No newline at end of file diff --git a/src/Exception/Parser/AbstractParserError.php b/src/Exception/Parser/AbstractParserError.php index 60bdc17b..403dfc6e 100644 --- a/src/Exception/Parser/AbstractParserError.php +++ b/src/Exception/Parser/AbstractParserError.php @@ -8,14 +8,14 @@ namespace Youshido\GraphQL\Exception\Parser; +use Exception; use Youshido\GraphQL\Exception\Interfaces\LocationableExceptionInterface; use Youshido\GraphQL\Parser\Location; -abstract class AbstractParserError extends \Exception implements LocationableExceptionInterface +abstract class AbstractParserError extends Exception implements LocationableExceptionInterface { - /** @var Location */ - private $location; + private readonly Location $location; public function __construct($message, Location $location) { diff --git a/src/Exception/ResolveException.php b/src/Exception/ResolveException.php index 9ff0fc84..45e1acd1 100644 --- a/src/Exception/ResolveException.php +++ b/src/Exception/ResolveException.php @@ -8,16 +8,16 @@ namespace Youshido\GraphQL\Exception; +use Exception; use Youshido\GraphQL\Exception\Interfaces\LocationableExceptionInterface; use Youshido\GraphQL\Parser\Location; -class ResolveException extends \Exception implements LocationableExceptionInterface +class ResolveException extends Exception implements LocationableExceptionInterface { - /** @var Location */ - private $location; + private readonly ?Location $location; - public function __construct($message, Location $location = null) + public function __construct($message, ?Location $location = null) { parent::__construct($message); @@ -26,9 +26,9 @@ public function __construct($message, Location $location = null) /** - * @return Location + * @return Location|null */ - public function getLocation() + public function getLocation(): ?Location { return $this->location; } diff --git a/src/Exception/ValidationException.php b/src/Exception/ValidationException.php index 4f1f0e57..5eaac1ab 100644 --- a/src/Exception/ValidationException.php +++ b/src/Exception/ValidationException.php @@ -8,7 +8,9 @@ namespace Youshido\GraphQL\Exception; -class ValidationException extends \Exception +use Exception; + +class ValidationException extends Exception { } \ No newline at end of file diff --git a/src/Execution/Container/Container.php b/src/Execution/Container/Container.php index 975f9d1b..ce145614 100644 --- a/src/Execution/Container/Container.php +++ b/src/Execution/Container/Container.php @@ -8,18 +8,23 @@ namespace Youshido\GraphQL\Execution\Container; +use Exception; +use RuntimeException; + class Container implements ContainerInterface { - private $keyset = []; - private $values = []; - private $services = []; + private array $keyset = []; + + private array $values = []; + + private array $services = []; /** * @param $id * @return mixed - * @throws \Exception if there was no value set under specified id + * @throws Exception if there was no value set under specified id */ public function get($id) { @@ -27,10 +32,11 @@ public function get($id) if (isset($this->services['id'])) { return $this->services['id']($this); } + return $this->values[$id]; } - public function set($id, $value) + public function set($id, $value): static { $this->values[$id] = $value; $this->keyset[$id] = true; @@ -40,36 +46,38 @@ public function set($id, $value) protected function setAsService($id, $service) { if (!is_object($service)) { - throw new \RuntimeException(sprintf('Service %s has to be an object', $id)); + throw new RuntimeException(sprintf('Service %s has to be an object', $id)); } $this->services[$id] = $service; if (isset($this->values[$id])) { unset($this->values[$id]); } - $this->keyset[$id] = true; + + $this->keyset[$id] = true; } - public function remove($id) + public function remove($id): void { $this->assertIdentifierSet($id); if (array_key_exists($id, $this->values)) { unset($this->values[$id]); } + if (array_key_exists($id, $this->services)) { unset($this->services[$id]); } } - public function has($id) + public function has($id): bool { return isset($this->keyset[$id]); } - private function assertIdentifierSet($id) + private function assertIdentifierSet($id): void { if (!$this->has($id)) { - throw new \RuntimeException(sprintf('Container item "%s" was not set', $id)); + throw new RuntimeException(sprintf('Container item "%s" was not set', $id)); } } } \ No newline at end of file diff --git a/src/Execution/Container/ContainerInterface.php b/src/Execution/Container/ContainerInterface.php index 4f79438a..1d3c9976 100644 --- a/src/Execution/Container/ContainerInterface.php +++ b/src/Execution/Container/ContainerInterface.php @@ -1,4 +1,5 @@ validateSchema(); $this->introduceIntrospectionFields(); - - $this->typeFieldLookupTable = []; } /** - * @param AbstractObjectType $type - * @param string $fieldName - * - * @return Field + * @return mixed - Field */ - public function getField(AbstractObjectType $type, $fieldName) + public function getField(AbstractObjectType $type, string $fieldName): mixed { $typeName = $type->getName(); @@ -72,56 +60,46 @@ public function getField(AbstractObjectType $type, $fieldName) return $this->typeFieldLookupTable[$typeName][$fieldName]; } - protected function validateSchema() + protected function validateSchema(): void { try { (new SchemaValidator())->validate($this->schema); - } catch (\Exception $e) { - $this->addError($e); - }; + } catch (Exception $exception) { + $this->addError($exception); + } } - protected function introduceIntrospectionFields() + protected function introduceIntrospectionFields(): void { $schemaField = new SchemaField(); $this->schema->addQueryField($schemaField); $this->schema->addQueryField(new TypeDefinitionField()); } - /** - * @return AbstractSchema - */ - public function getSchema() + public function getSchema(): AbstractSchema { return $this->schema; } /** - * @param AbstractSchema $schema - * * @return $this */ - public function setSchema(AbstractSchema $schema) + public function setSchema(AbstractSchema $schema): static { $this->schema = $schema; return $this; } - /** - * @return Request - */ - public function getRequest() + public function getRequest(): ?Request { return $this->request; } /** - * @param Request $request - * * @return $this */ - public function setRequest(Request $request) + public function setRequest(Request $request): static { $this->request = $request; @@ -133,23 +111,18 @@ public function get($id) return $this->container->get($id); } - /** - * @return ContainerInterface - */ - public function getContainer() + public function getContainer(): ?ContainerInterface { return $this->container; } /** - * @param ContainerInterface $container - * * @return $this */ - public function setContainer(ContainerInterface $container) + public function setContainer(ContainerInterface $container): static { $this->container = $container; return $this; } -} +} \ No newline at end of file diff --git a/src/Execution/Context/ExecutionContextInterface.php b/src/Execution/Context/ExecutionContextInterface.php index 0845c237..93d9d199 100644 --- a/src/Execution/Context/ExecutionContextInterface.php +++ b/src/Execution/Context/ExecutionContextInterface.php @@ -22,8 +22,6 @@ interface ExecutionContextInterface extends ErrorContainerInterface public function getSchema(); /** - * @param AbstractSchema $schema - * * @return $this */ public function setSchema(AbstractSchema $schema); @@ -34,8 +32,6 @@ public function setSchema(AbstractSchema $schema); public function getRequest(); /** - * @param Request $request - * * @return $this */ public function setRequest(Request $request); @@ -46,7 +42,6 @@ public function setRequest(Request $request); public function getContainer(); /** - * @param ContainerInterface $container * @return mixed */ public function setContainer(ContainerInterface $container); diff --git a/src/Execution/DeferredResolver.php b/src/Execution/DeferredResolver.php index 9414dac7..99c8e13a 100644 --- a/src/Execution/DeferredResolver.php +++ b/src/Execution/DeferredResolver.php @@ -14,7 +14,8 @@ * * @package Youshido\GraphQL\Execution */ -class DeferredResolver implements DeferredResolverInterface { +class DeferredResolver implements DeferredResolverInterface +{ /** @var callable */ private $resolver; @@ -24,7 +25,8 @@ public function __construct($resolver) $this->resolver = $resolver; } - public function resolve() { - return call_user_func($this->resolver); + public function resolve(): mixed + { + return call_user_func($this->resolver); } } \ No newline at end of file diff --git a/src/Execution/DeferredResolverInterface.php b/src/Execution/DeferredResolverInterface.php index 63cb80cd..58d74012 100644 --- a/src/Execution/DeferredResolverInterface.php +++ b/src/Execution/DeferredResolverInterface.php @@ -14,12 +14,13 @@ * Fields may return a value implementing this interface to use deferred * resolving to optimize query performance. */ -interface DeferredResolverInterface { +interface DeferredResolverInterface +{ - /** - * @return mixed - * The actual result value. - */ - public function resolve(); + /** + * @return mixed + * The actual result value. + */ + public function resolve(); } diff --git a/src/Execution/DeferredResult.php b/src/Execution/DeferredResult.php index ffca890b..21ed8271 100644 --- a/src/Execution/DeferredResult.php +++ b/src/Execution/DeferredResult.php @@ -8,23 +8,22 @@ namespace Youshido\GraphQL\Execution; - /** * Wrapper class for deferred resolvers during execution process. * Not part of the public API. * * @internal */ -class DeferredResult implements DeferredResolverInterface { +class DeferredResult implements DeferredResolverInterface +{ - /** @var \Youshido\GraphQL\Execution\DeferredResolver */ - private $resolver; + /** @var DeferredResolver */ + private readonly DeferredResolverInterface $resolver; /** @var callable */ protected $callback; - /** @var mixed */ - public $result; + public mixed $result; public function __construct(DeferredResolverInterface $resolver, callable $callback) { @@ -32,7 +31,8 @@ public function __construct(DeferredResolverInterface $resolver, callable $callb $this->callback = $callback; } - public function resolve() { + public function resolve(): void + { $this->result = call_user_func($this->callback, $this->resolver->resolve()); } } \ No newline at end of file diff --git a/src/Execution/Processor.php b/src/Execution/Processor.php index e4aac98c..c40893d9 100644 --- a/src/Execution/Processor.php +++ b/src/Execution/Processor.php @@ -7,10 +7,15 @@ namespace Youshido\GraphQL\Execution; - +use Exception; +use InvalidArgumentException; +use Youshido\GraphQL\Exception\ConfigurationException; +use Youshido\GraphQL\Exception\Parser\InvalidRequestException; +use Youshido\GraphQL\Exception\Parser\SyntaxErrorException; use Youshido\GraphQL\Exception\ResolveException; use Youshido\GraphQL\Execution\Container\Container; use Youshido\GraphQL\Execution\Context\ExecutionContext; +use Youshido\GraphQL\Execution\Context\ExecutionContextInterface; use Youshido\GraphQL\Execution\Visitor\MaxComplexityQueryVisitor; use Youshido\GraphQL\Field\Field; use Youshido\GraphQL\Field\FieldInterface; @@ -20,6 +25,7 @@ use Youshido\GraphQL\Parser\Ast\ArgumentValue\Literal as AstLiteral; use Youshido\GraphQL\Parser\Ast\ArgumentValue\VariableReference; use Youshido\GraphQL\Parser\Ast\Field as AstField; +use Youshido\GraphQL\Parser\Ast\Fragment; use Youshido\GraphQL\Parser\Ast\FragmentReference; use Youshido\GraphQL\Parser\Ast\Interfaces\FieldInterface as AstFieldInterface; use Youshido\GraphQL\Parser\Ast\Mutation as AstMutation; @@ -43,25 +49,19 @@ class Processor { - const TYPE_NAME_QUERY = '__typename'; + final const TYPE_NAME_QUERY = '__typename'; - /** @var ExecutionContext */ - protected $executionContext; + protected ExecutionContextInterface $executionContext; - /** @var ResolveValidatorInterface */ - protected $resolveValidator; + protected ResolveValidatorInterface $resolveValidator; - /** @var array */ - protected $data; + protected array $data = []; - /** @var int */ - protected $maxComplexity; + protected ?int $maxComplexity = null; - /** @var array DeferredResult[] */ - protected $deferredResultsLeaf = []; + protected array $deferredResultsLeaf = []; - /** @var array DeferredResult[] */ - protected $deferredResultsComplex = []; + protected array $deferredResultsComplex = []; public function __construct(AbstractSchema $schema) { @@ -73,22 +73,22 @@ public function __construct(AbstractSchema $schema) $this->resolveValidator = new ResolveValidator($this->executionContext); } - public function processPayload($payload, $variables = [], $reducers = []) + public function processPayload($payload, $variables = [], array $reducers = []): static { $this->data = []; try { $this->parseAndCreateRequest($payload, $variables); - if ($this->maxComplexity) { + if ($this->maxComplexity !== null && $this->maxComplexity !== 0) { $reducers[] = new MaxComplexityQueryVisitor($this->maxComplexity); } - if ($reducers) { + if ($reducers !== []) { $reducer = new Reducer(); $reducer->reduceQuery($this->executionContext, $reducers); } - + // Resolve all queries/operations and merge their data at the end $operationResults = []; @@ -97,30 +97,30 @@ public function processPayload($payload, $variables = [], $reducers = []) $operationResults[] = $operationResult; } } - + $this->data = $this->combineResults($operationResults); // If the processor found any deferred results, resolve them now. - if (!empty($this->data) && (!empty($this->deferredResultsLeaf) || !empty($this->deferredResultsComplex))) { - try { - while ($deferredResolver = array_shift($this->deferredResultsComplex)) { - $deferredResolver->resolve(); - } - - // Deferred scalar and enum fields should be resolved last to - // pick up as many as possible for a single batch. - while ($deferredResolver = array_shift($this->deferredResultsLeaf)) { - $deferredResolver->resolve(); - } - } catch (\Exception $e) { - $this->executionContext->addError($e); - } finally { - $this->data = static::unpackDeferredResults($this->data); - } + if ($this->data !== [] && ($this->deferredResultsLeaf !== [] || $this->deferredResultsComplex !== [])) { + try { + while ($deferredResolver = array_shift($this->deferredResultsComplex)) { + $deferredResolver->resolve(); + } + + // Deferred scalar and enum fields should be resolved last to + // pick up as many as possible for a single batch. + while ($deferredResolver = array_shift($this->deferredResultsLeaf)) { + $deferredResolver->resolve(); + } + } catch (Exception $e) { + $this->executionContext->addError($e); + } finally { + $this->data = static::unpackDeferredResults($this->data); + } } - } catch (\Exception $e) { - $this->executionContext->addError($e); + } catch (Exception $exception) { + $this->executionContext->addError($exception); } return $this; @@ -135,7 +135,7 @@ public function processPayload($payload, $variables = [], $reducers = []) * @return mixed * The unpacked result. */ - public static function unpackDeferredResults($result) + public static function unpackDeferredResults(mixed $result): mixed { while ($result instanceof DeferredResult) { $result = $result->result; @@ -150,16 +150,20 @@ public static function unpackDeferredResults($result) return $result; } - protected function resolveQuery(AstQuery $query) + /** + * @throws ResolveException + * @throws ConfigurationException + */ + protected function resolveQuery(AstQuery $query): array { $schema = $this->executionContext->getSchema(); - $type = $query instanceof AstMutation ? $schema->getMutationType() : $schema->getQueryType(); - $field = new Field([ + $type = $query instanceof AstMutation ? $schema->getMutationType() : $schema->getQueryType(); + $field = new Field([ 'name' => $query instanceof AstMutation ? 'mutation' : 'query', 'type' => $type ]); - if (self::TYPE_NAME_QUERY == $query->getName()) { + if (self::TYPE_NAME_QUERY === $query->getName()) { return [$this->getAlias($query) => $type->getName()]; } @@ -169,14 +173,17 @@ protected function resolveQuery(AstQuery $query) return [$this->getAlias($query) => $value]; } + /** + * @throws ResolveException + */ protected function resolveField(FieldInterface $field, AstFieldInterface $ast, $parentValue = null, $fromObject = false) { try { /** @var AbstractObjectType $type */ - $type = $field->getType(); + $type = $field->getType(); $nonNullType = $type->getNullableType(); - if (self::TYPE_NAME_QUERY == $ast->getName()) { + if (self::TYPE_NAME_QUERY === $ast->getName()) { return $nonNullType->getName(); } @@ -218,18 +225,21 @@ protected function resolveField(FieldInterface $field, AstFieldInterface $ast, $ default: throw new ResolveException(sprintf('Resolving type with kind "%s" not supported', $kind)); } - } catch (\Exception $e) { - $this->executionContext->addError($e); + } catch (Exception $exception) { + $this->executionContext->addError($exception); if ($fromObject) { - throw $e; + throw $exception; } return null; } } - private function prepareAstArguments(FieldInterface $field, AstFieldInterface $query, Request $request) + /** + * @throws ResolveException + */ + private function prepareAstArguments(FieldInterface $field, AstFieldInterface $query, Request $request): void { foreach ($query->getArguments() as $astArgument) { if ($field->hasArgument($astArgument->getName())) { @@ -240,6 +250,9 @@ private function prepareAstArguments(FieldInterface $field, AstFieldInterface $q } } + /** + * @throws ResolveException + */ private function prepareArgumentValue($argumentValue, AbstractType $argumentType, Request $request) { switch ($argumentType->getKind()) { @@ -251,10 +264,8 @@ private function prepareArgumentValue($argumentValue, AbstractType $argumentType foreach ($list as $item) { $result[] = $this->prepareArgumentValue($item, $argumentType->getItemType()->getNullableType(), $request); } - } else { - if ($argumentValue instanceof VariableReference) { - return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request); - } + } elseif ($argumentValue instanceof VariableReference) { + return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request); } return $result; @@ -269,6 +280,7 @@ private function prepareArgumentValue($argumentValue, AbstractType $argumentType $result[$field->getName()] = $field->getType()->getNullableType()->parseInputValue($field->getConfig()->get('defaultValue')); } } + foreach ($argumentValue->getValue() as $key => $item) { if ($argumentType->hasField($key)) { $result[$key] = $this->prepareArgumentValue($item, $argumentType->getField($key)->getType()->getNullableType(), $request); @@ -276,14 +288,10 @@ private function prepareArgumentValue($argumentValue, AbstractType $argumentType $result[$key] = $item; } } - } else { - if ($argumentValue instanceof VariableReference) { - return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request); - } else { - if (is_array($argumentValue)) { - return $argumentValue; - } - } + } elseif ($argumentValue instanceof VariableReference) { + return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request); + } elseif (is_array($argumentValue)) { + return $argumentValue; } return $result; @@ -293,18 +301,19 @@ private function prepareArgumentValue($argumentValue, AbstractType $argumentType /** @var $argumentValue AstLiteral|VariableReference */ if ($argumentValue instanceof VariableReference) { return $this->getVariableReferenceArgumentValue($argumentValue, $argumentType, $request); + } elseif ($argumentValue instanceof AstLiteral) { + return $argumentValue->getValue(); } else { - if ($argumentValue instanceof AstLiteral) { - return $argumentValue->getValue(); - } else { - return $argumentValue; - } + return $argumentValue; } } throw new ResolveException('Argument type not supported'); } + /** + * @throws ResolveException + */ private function getVariableReferenceArgumentValue(VariableReference $variableReference, AbstractType $argumentType, Request $request) { $variable = $variableReference->getVariable(); @@ -316,10 +325,8 @@ private function getVariableReferenceArgumentValue(VariableReference $variableRe ) { throw new ResolveException(sprintf('Invalid variable "%s" type, allowed type is "%s"', $variable->getName(), $argumentType->getNamedType()->getNullableType()->getName()), $variable->getLocation()); } - } else { - if ($variable->getTypeName() !== $argumentType->getName()) { - throw new ResolveException(sprintf('Invalid variable "%s" type, allowed type is "%s"', $variable->getName(), $argumentType->getName()), $variable->getLocation()); - } + } elseif ($variable->getTypeName() !== $argumentType->getName()) { + throw new ResolveException(sprintf('Invalid variable "%s" type, allowed type is "%s"', $variable->getName(), $argumentType->getName()), $variable->getLocation()); } $requestValue = $request->getVariable($variable->getName()); @@ -332,20 +339,17 @@ private function getVariableReferenceArgumentValue(VariableReference $variableRe /** - * @param FieldInterface $field - * @param AbstractObjectType $type - * @param AstFieldInterface $ast - * @param $resolvedValue - * @return array + * @param $resolvedValue + * @throws ResolveException */ - private function collectResult(FieldInterface $field, AbstractObjectType $type, $ast, $resolvedValue) + private function collectResult(FieldInterface $field, AbstractObjectType $type, Fragment|AstFieldInterface|TypedFragmentReference $ast, $resolvedValue): array { $results = []; foreach ($ast->getFields() as $astField) { switch (true) { case $astField instanceof TypedFragmentReference: - $astName = $astField->getTypeName(); + $astName = $astField->getTypeName(); $typeName = $type->getName(); if ($typeName !== $astName) { @@ -365,9 +369,9 @@ private function collectResult(FieldInterface $field, AbstractObjectType $type, break; case $astField instanceof FragmentReference: - $astFragment = $this->executionContext->getRequest()->getFragment($astField->getName()); + $astFragment = $this->executionContext->getRequest()->getFragment($astField->getName()); $astFragmentModel = $astFragment->getModel(); - $typeName = $type->getName(); + $typeName = $type->getName(); if ($typeName !== $astFragmentModel) { foreach ($type->getInterfaces() as $interface) { @@ -396,7 +400,8 @@ private function collectResult(FieldInterface $field, AbstractObjectType $type, /** * Apply post-process callbacks to all deferred resolvers. */ - protected function deferredResolve($resolvedValue, FieldInterface $field, callable $callback) { + protected function deferredResolve($resolvedValue, FieldInterface $field, callable $callback): mixed + { if ($resolvedValue instanceof DeferredResolverInterface) { $deferredResult = new DeferredResult($resolvedValue, function ($resolvedValue) use ($field, $callback) { // Allow nested deferred resolvers. @@ -414,14 +419,19 @@ protected function deferredResolve($resolvedValue, FieldInterface $field, callab return $deferredResult; } + // For simple values, invoke the callback immediately. return $callback($resolvedValue); } - protected function resolveScalar(FieldInterface $field, AstFieldInterface $ast, $parentValue) + /** + * @param $parentValue + * @throws ResolveException + */ + protected function resolveScalar(FieldInterface $field, AstFieldInterface $ast, $parentValue): mixed { $resolvedValue = $this->doResolve($field, $ast, $parentValue); - return $this->deferredResolve($resolvedValue, $field, function($resolvedValue) use ($field) { + return $this->deferredResolve($resolvedValue, $field, function ($resolvedValue) use ($field) { $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue); /** @var AbstractScalarType $type */ @@ -431,12 +441,17 @@ protected function resolveScalar(FieldInterface $field, AstFieldInterface $ast, }); } - protected function resolveList(FieldInterface $field, AstFieldInterface $ast, $parentValue) + /** + * @param $parentValue + * @throws ResolveException + * @throws ConfigurationException + */ + protected function resolveList(FieldInterface $field, AstFieldInterface $ast, $parentValue): mixed { /** @var AstQuery $ast */ $resolvedValue = $this->doResolve($field, $ast, $parentValue); - return $this->deferredResolve($resolvedValue, $field, function ($resolvedValue) use ($field, $ast) { + return $this->deferredResolve($resolvedValue, $field, function ($resolvedValue) use ($field, $ast): ?array { $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue); if (null === $resolvedValue) { @@ -444,7 +459,7 @@ protected function resolveList(FieldInterface $field, AstFieldInterface $ast, $p } /** @var AbstractListType $type */ - $type = $field->getType()->getNullableType(); + $type = $field->getType()->getNullableType(); $itemType = $type->getNamedType(); $fakeAst = clone $ast; @@ -453,41 +468,25 @@ protected function resolveList(FieldInterface $field, AstFieldInterface $ast, $p } $fakeField = new Field([ - 'name' => $field->getName(), - 'type' => $itemType, - 'args' => $field->getArguments(), + 'name' => $field->getName(), + 'type' => $itemType, + 'args' => $field->getArguments(), ]); $result = []; foreach ($resolvedValue as $resolvedValueItem) { try { - $fakeField->getConfig()->set('resolve', function () use ($resolvedValueItem) { + $fakeField->getConfig()->set('resolve', static function () use ($resolvedValueItem) { return $resolvedValueItem; }); - switch ($itemType->getNullableType()->getKind()) { - case TypeMap::KIND_ENUM: - case TypeMap::KIND_SCALAR: - $value = $this->resolveScalar($fakeField, $fakeAst, $resolvedValueItem); - - break; - - - case TypeMap::KIND_OBJECT: - $value = $this->resolveObject($fakeField, $fakeAst, $resolvedValueItem); - - break; - - case TypeMap::KIND_UNION: - case TypeMap::KIND_INTERFACE: - $value = $this->resolveComposite($fakeField, $fakeAst, $resolvedValueItem); - - break; - - default: - $value = null; - } - } catch (\Exception $e) { + $value = match ($itemType->getNullableType()->getKind()) { + TypeMap::KIND_ENUM, TypeMap::KIND_SCALAR => $this->resolveScalar($fakeField, $fakeAst, $resolvedValueItem), + TypeMap::KIND_OBJECT => $this->resolveObject($fakeField, $fakeAst, $resolvedValueItem), + TypeMap::KIND_UNION, TypeMap::KIND_INTERFACE => $this->resolveComposite($fakeField, $fakeAst, $resolvedValueItem), + default => null, + }; + } catch (Exception $e) { $this->executionContext->addError($e); $value = null; @@ -500,31 +499,41 @@ protected function resolveList(FieldInterface $field, AstFieldInterface $ast, $p }); } - protected function resolveObject(FieldInterface $field, AstFieldInterface $ast, $parentValue, $fromUnion = false) + /** + * @param $parentValue + * @throws ResolveException + */ + protected function resolveObject(FieldInterface $field, AstFieldInterface $ast, $parentValue, bool $fromUnion = false): mixed { $resolvedValue = $parentValue; if (!$fromUnion) { $resolvedValue = $this->doResolve($field, $ast, $parentValue); } - return $this->deferredResolve($resolvedValue, $field, function ($resolvedValue) use ($field, $ast) { + return $this->deferredResolve($resolvedValue, $field, function ($resolvedValue) use ($field, $ast): ?array { $this->resolveValidator->assertValidResolvedValueForField($field, $resolvedValue); if (null === $resolvedValue) { return null; } + /** @var AbstractObjectType $type */ $type = $field->getType()->getNullableType(); try { return $this->collectResult($field, $type, $ast, $resolvedValue); - } catch (\Exception $e) { + } catch (Exception) { return null; } }); } - protected function resolveComposite(FieldInterface $field, AstFieldInterface $ast, $parentValue) + /** + * @param $parentValue + * @throws ResolveException + * @throws ConfigurationException + */ + protected function resolveComposite(FieldInterface $field, AstFieldInterface $ast, $parentValue): mixed { /** @var AstQuery $ast */ $resolvedValue = $this->doResolve($field, $ast, $parentValue); @@ -536,13 +545,8 @@ protected function resolveComposite(FieldInterface $field, AstFieldInterface $as } /** @var AbstractUnionType $type */ - $type = $field->getType()->getNullableType(); - $resolveInfo = new ResolveInfo( - $field, - $ast instanceof AstQuery ? $ast->getFields() : [], - $this->executionContext - ); - $resolvedType = $type->resolveType($resolvedValue, $resolveInfo); + $type = $field->getType()->getNullableType(); + $resolvedType = $type->resolveType($resolvedValue); if (!$resolvedType) { throw new ResolveException('Resolving function must return type'); @@ -555,22 +559,26 @@ protected function resolveComposite(FieldInterface $field, AstFieldInterface $as } $fakeField = new Field([ - 'name' => $field->getName(), - 'type' => $resolvedType, - 'args' => $field->getArguments(), + 'name' => $field->getName(), + 'type' => $resolvedType, + 'args' => $field->getArguments(), ]); return $this->resolveObject($fakeField, $ast, $resolvedValue, true); }); } - protected function parseAndCreateRequest($payload, $variables = []) + /** + * @throws SyntaxErrorException + * @throws InvalidRequestException + */ + protected function parseAndCreateRequest($payload, $variables = []): void { if (empty($payload)) { - throw new \InvalidArgumentException('Must provide an operation.'); + throw new InvalidArgumentException('Must provide an operation.'); } - $parser = new Parser(); + $parser = new Parser(); $request = new Request($parser->parse($payload), $variables); (new RequestValidator())->validate($request); @@ -578,7 +586,7 @@ protected function parseAndCreateRequest($payload, $variables = []) $this->executionContext->setRequest($request); } - protected function doResolve(FieldInterface $field, AstFieldInterface $ast, $parentValue = null) + protected function doResolve(FieldInterface $field, AstFieldInterface $ast, $parentValue = null): mixed { /** @var AstQuery|AstField $ast */ $arguments = $this->parseArgumentsValues($field, $ast); @@ -587,9 +595,9 @@ protected function doResolve(FieldInterface $field, AstFieldInterface $ast, $par return $field->resolve($parentValue, $arguments, $this->createResolveInfo($field, $astFields)); } - protected function parseArgumentsValues(FieldInterface $field, AstFieldInterface $ast) + protected function parseArgumentsValues(FieldInterface $field, AstFieldInterface $ast): array { - $values = []; + $values = []; $defaults = []; foreach ($field->getArguments() as $argument) { @@ -600,7 +608,7 @@ protected function parseArgumentsValues(FieldInterface $field, AstFieldInterface } foreach ($ast->getArguments() as $astArgument) { - $argument = $field->getArgument($astArgument->getName()); + $argument = $field->getArgument($astArgument->getName()); $argumentType = $argument->getType()->getNullableType(); $values[$argument->getName()] = $argumentType->parseValue($astArgument->getValue()); @@ -613,27 +621,23 @@ protected function parseArgumentsValues(FieldInterface $field, AstFieldInterface return array_merge($values, $defaults); } - private function getAlias(AstFieldInterface $ast) + private function getAlias(AstFieldInterface $ast): string { return $ast->getAlias() ?: $ast->getName(); } - protected function createResolveInfo(FieldInterface $field, array $astFields) + protected function createResolveInfo(FieldInterface $field, array $astFields): ResolveInfo { return new ResolveInfo($field, $astFields, $this->executionContext); } /** * Combines the specified results using array_replace_recursive, including graceful handling for empty arrays - * - * @param array $results - * - * @return array */ - protected function combineResults(array $results) + protected function combineResults(array $results): array { - if (count($results) > 0) { - return call_user_func_array('array_replace_recursive', $results); + if ($results !== []) { + return array_replace_recursive(...$results); } return []; @@ -641,19 +645,17 @@ protected function combineResults(array $results) /** * You can access ExecutionContext to check errors and inject dependencies - * - * @return ExecutionContext */ - public function getExecutionContext() + public function getExecutionContext(): ExecutionContext { return $this->executionContext; } - public function getResponseData() + public function getResponseData(): array { $result = []; - if (!empty($this->data)) { + if ($this->data !== []) { $result['data'] = $this->data; } @@ -664,20 +666,13 @@ public function getResponseData() return $result; } - /** - * @return int - */ - public function getMaxComplexity() + public function getMaxComplexity(): ?int { return $this->maxComplexity; } - /** - * @param int $maxComplexity - */ - public function setMaxComplexity($maxComplexity) + public function setMaxComplexity(?int $maxComplexity): void { $this->maxComplexity = $maxComplexity; } - -} +} \ No newline at end of file diff --git a/src/Execution/Reducer.php b/src/Execution/Reducer.php index a74c122e..7763544f 100644 --- a/src/Execution/Reducer.php +++ b/src/Execution/Reducer.php @@ -8,6 +8,7 @@ namespace Youshido\GraphQL\Execution; +use Generator; use Youshido\GraphQL\Execution\Context\ExecutionContextInterface; use Youshido\GraphQL\Execution\Visitor\AbstractQueryVisitor; use Youshido\GraphQL\Field\Field; @@ -24,20 +25,18 @@ class Reducer { - /** @var ExecutionContextInterface */ - private $executionContext; + private ?ExecutionContextInterface $executionContext = null; /** * Apply all of $reducers to this query. Example reducer operations: checking for maximum query complexity, * performing look-ahead query planning, etc. * - * @param ExecutionContextInterface $executionContext - * @param AbstractQueryVisitor[] $reducers + * @param AbstractQueryVisitor[] $reducers */ - public function reduceQuery(ExecutionContextInterface $executionContext, array $reducers) + public function reduceQuery(ExecutionContextInterface $executionContext, array $reducers): void { $this->executionContext = $executionContext; - $schema = $executionContext->getSchema(); + $schema = $executionContext->getSchema(); foreach ($reducers as $reducer) { foreach ($executionContext->getRequest()->getAllOperations() as $operation) { @@ -50,8 +49,7 @@ public function reduceQuery(ExecutionContextInterface $executionContext, array $ * Entry point for the `walkQuery` routine. Execution bounces between here, where the reducer's ->visit() method * is invoked, and `walkQuery` where we send in the scores from the `visit` call. * - * @param Query $query - * @param AbstractType $currentLevelSchema + * @param AbstractType $currentLevelSchema * @param AbstractQueryVisitor $reducer */ protected function doVisit(Query $query, $currentLevelSchema, $reducer) @@ -72,7 +70,7 @@ protected function doVisit(Query $query, $currentLevelSchema, $reducer) /** * @var Query|FieldAst $queryField - * @var Field $astField + * @var Field $astField */ $cost = $reducer->visit($queryField->getKeyValueArguments(), $astField->getConfig(), $childCost); $queryCost += $cost; @@ -92,10 +90,9 @@ protected function doVisit(Query $query, $currentLevelSchema, $reducer) * Fragments (anonymous and named), and Fields. The core of the function is simple: recurse until we hit the base * case of a Field and yield that back up to the visitor up in `doVisit`. * - * @param Query|Field|\Youshido\GraphQL\Parser\Ast\Interfaces\FragmentInterface $queryNode - * @param FieldInterface $currentLevelAST + * @param Query|Field|FragmentInterface $queryNode * - * @return \Generator + * @return Generator */ protected function walkQuery($queryNode, FieldInterface $currentLevelAST) { @@ -106,11 +103,12 @@ protected function walkQuery($queryNode, FieldInterface $currentLevelAST) if ($queryField instanceof FragmentReference) { $queryField = $this->executionContext->getRequest()->getFragment($queryField->getName()); } + // the next 7 lines are essentially equivalent to `yield from $this->walkQuery(...)` in PHP7. // for backwards compatibility this is equivalent. // This pattern is repeated multiple times in this function, and unfortunately cannot be extracted or // made less verbose. - $gen = $this->walkQuery($queryField, $currentLevelAST); + $gen = $this->walkQuery($queryField, $currentLevelAST); $next = $gen->current(); while ($next) { $received = (yield $next); @@ -122,7 +120,7 @@ protected function walkQuery($queryNode, FieldInterface $currentLevelAST) if ($fieldType instanceof AbstractUnionType) { foreach ($fieldType->getTypes() as $unionFieldType) { if ($fieldAst = $unionFieldType->getField($queryField->getName())) { - $gen = $this->walkQuery($queryField, $fieldAst); + $gen = $this->walkQuery($queryField, $fieldAst); $next = $gen->current(); while ($next) { $received = (yield $next); @@ -132,7 +130,7 @@ protected function walkQuery($queryNode, FieldInterface $currentLevelAST) } } } elseif ($fieldType instanceof AbstractObjectType && $fieldAst = $fieldType->getField($queryField->getName())) { - $gen = $this->walkQuery($queryField, $fieldAst); + $gen = $this->walkQuery($queryField, $fieldAst); $next = $gen->current(); while ($next) { $received = (yield $next); @@ -143,6 +141,7 @@ protected function walkQuery($queryNode, FieldInterface $currentLevelAST) } } } + // sanity check. don't yield fragments; they don't contribute to cost if ($queryNode instanceof Query || $queryNode instanceof FieldAst) { // BASE CASE. If we're here we're done recursing - diff --git a/src/Execution/Request.php b/src/Execution/Request.php index 5b3da1a0..9479087b 100644 --- a/src/Execution/Request.php +++ b/src/Execution/Request.php @@ -19,27 +19,28 @@ class Request { /** @var Query[] */ - private $queries = []; + private array $queries = []; /** @var Fragment[] */ - private $fragments = []; + private array $fragments = []; /** @var Mutation[] */ - private $mutations = []; + private array $mutations = []; /** @var array */ private $variables = []; /** @var VariableReference[] */ - private $variableReferences = []; + private array $variableReferences = []; - /** @var array */ - private $queryVariables = []; + private array $queryVariables = []; - /** @var array */ - private $fragmentReferences = []; + private array $fragmentReferences = []; - public function __construct($data = [], $variables = []) + /** + * @throws InvalidRequestException + */ + public function __construct(array $data = [], array $variables = []) { if (array_key_exists('queries', $data)) { $this->addQueries($data['queries']); @@ -70,6 +71,7 @@ public function __construct($data = [], $variables = []) $variables[$variable->getName()] = $variable->getDefaultValue()->getValue(); continue; } + throw new InvalidRequestException(sprintf("Variable %s hasn't been submitted", $ref->getName()), $ref->getLocation()); } } @@ -80,42 +82,42 @@ public function __construct($data = [], $variables = []) $this->setVariables($variables); } - public function addQueries($queries) + public function addQueries($queries): void { foreach ($queries as $query) { $this->queries[] = $query; } } - public function addMutations($mutations) + public function addMutations($mutations): void { foreach ($mutations as $mutation) { $this->mutations[] = $mutation; } } - public function addQueryVariables($queryVariables) + public function addQueryVariables($queryVariables): void { foreach ($queryVariables as $queryVariable) { $this->queryVariables[] = $queryVariable; } } - public function addVariableReferences($variableReferences) + public function addVariableReferences($variableReferences): void { foreach ($variableReferences as $variableReference) { $this->variableReferences[] = $variableReference; } } - public function addFragmentReferences($fragmentReferences) + public function addFragmentReferences($fragmentReferences): void { foreach ($fragmentReferences as $fragmentReference) { $this->fragmentReferences[] = $fragmentReference; } } - public function addFragments($fragments) + public function addFragments($fragments): void { foreach ($fragments as $fragment) { $this->addFragment($fragment); @@ -125,7 +127,7 @@ public function addFragments($fragments) /** * @return Query[] */ - public function getAllOperations() + public function getAllOperations(): array { return array_merge($this->mutations, $this->queries); } @@ -133,7 +135,7 @@ public function getAllOperations() /** * @return Query[] */ - public function getQueries() + public function getQueries(): array { return $this->queries; } @@ -141,22 +143,20 @@ public function getQueries() /** * @return Fragment[] */ - public function getFragments() + public function getFragments(): array { return $this->fragments; } - public function addFragment(Fragment $fragment) + public function addFragment(Fragment $fragment): void { $this->fragments[] = $fragment; } /** * @param $name - * - * @return null|Fragment */ - public function getFragment($name) + public function getFragment($name): ?Fragment { foreach ($this->fragments as $fragment) { if ($fragment->getName() == $name) { @@ -170,31 +170,22 @@ public function getFragment($name) /** * @return Mutation[] */ - public function getMutations() + public function getMutations(): array { return $this->mutations; } - /** - * @return bool - */ - public function hasQueries() + public function hasQueries(): bool { return (bool)count($this->queries); } - /** - * @return bool - */ - public function hasMutations() + public function hasMutations(): bool { return (bool)count($this->mutations); } - /** - * @return bool - */ - public function hasFragments() + public function hasFragments(): bool { return (bool)count($this->fragments); } @@ -212,7 +203,7 @@ public function getVariables() * * @return $this */ - public function setVariables($variables) + public function setVariables($variables): static { if (!is_array($variables)) { $variables = json_decode($variables, true); @@ -221,11 +212,16 @@ public function setVariables($variables) $this->variables = $variables; foreach ($this->variableReferences as $reference) { /** invalid request with no variable */ - if (!$reference->getVariable()) continue; + if (!$reference->getVariable()) { + continue; + } + $variableName = $reference->getVariable()->getName(); /** no variable was set at the time */ - if (!array_key_exists($variableName, $variables)) continue; + if (!array_key_exists($variableName, $variables)) { + continue; + } $reference->getVariable()->setValue($variables[$variableName]); $reference->setValue($variables[$variableName]); @@ -239,7 +235,7 @@ public function getVariable($name) return $this->hasVariable($name) ? $this->variables[$name] : null; } - public function hasVariable($name) + public function hasVariable($name): bool { return array_key_exists($name, $this->variables); } @@ -247,15 +243,12 @@ public function hasVariable($name) /** * @return array|Variable[] */ - public function getQueryVariables() + public function getQueryVariables(): array { return $this->queryVariables; } - /** - * @param array $queryVariables - */ - public function setQueryVariables($queryVariables) + public function setQueryVariables(array $queryVariables): void { $this->queryVariables = $queryVariables; } @@ -263,15 +256,12 @@ public function setQueryVariables($queryVariables) /** * @return array|FragmentReference[] */ - public function getFragmentReferences() + public function getFragmentReferences(): array { return $this->fragmentReferences; } - /** - * @param array $fragmentReferences - */ - public function setFragmentReferences($fragmentReferences) + public function setFragmentReferences(array $fragmentReferences): void { $this->fragmentReferences = $fragmentReferences; } @@ -279,7 +269,7 @@ public function setFragmentReferences($fragmentReferences) /** * @return array|VariableReference[] */ - public function getVariableReferences() + public function getVariableReferences(): array { return $this->variableReferences; } diff --git a/src/Execution/ResolveInfo.php b/src/Execution/ResolveInfo.php index aa9cc21b..4402be05 100644 --- a/src/Execution/ResolveInfo.php +++ b/src/Execution/ResolveInfo.php @@ -16,14 +16,12 @@ class ResolveInfo { - /** @var FieldInterface */ - protected $field; + protected FieldInterface $field; /** @var Field[] */ - protected $fieldASTList; + protected array $fieldASTList; - /** @var ExecutionContextInterface */ - protected $executionContext; + protected ExecutionContextInterface $executionContext; /** * This property is to be used for DI in various scenario @@ -36,23 +34,17 @@ class ResolveInfo public function __construct(FieldInterface $field, array $fieldASTList, ExecutionContextInterface $executionContext) { - $this->field = $field; - $this->fieldASTList = $fieldASTList; + $this->field = $field; + $this->fieldASTList = $fieldASTList; $this->executionContext = $executionContext; } - /** - * @return ExecutionContextInterface - */ - public function getExecutionContext() + public function getExecutionContext(): ExecutionContextInterface { return $this->executionContext; } - /** - * @return FieldInterface - */ - public function getField() + public function getField(): FieldInterface { return $this->field; } @@ -78,7 +70,7 @@ public function getFieldAST($fieldName) /** * @return Field[] */ - public function getFieldASTList() + public function getFieldASTList(): array { return $this->fieldASTList; } @@ -86,7 +78,7 @@ public function getFieldASTList() /** * @return AbstractType */ - public function getReturnType() + public function getReturnType(): mixed { return $this->field->getType(); } diff --git a/src/Execution/Visitor/AbstractQueryVisitor.php b/src/Execution/Visitor/AbstractQueryVisitor.php index 5b19f137..c40d2254 100644 --- a/src/Execution/Visitor/AbstractQueryVisitor.php +++ b/src/Execution/Visitor/AbstractQueryVisitor.php @@ -59,9 +59,7 @@ public function getMemo() /** * Visit a query node. See class docstring. * - * @param array $args - * @param FieldConfig $fieldConfig - * @param int $childScore + * @param int $childScore * * @return int|null */ diff --git a/src/Execution/Visitor/MaxComplexityQueryVisitor.php b/src/Execution/Visitor/MaxComplexityQueryVisitor.php index 242193fe..045e1060 100644 --- a/src/Execution/Visitor/MaxComplexityQueryVisitor.php +++ b/src/Execution/Visitor/MaxComplexityQueryVisitor.php @@ -11,28 +11,27 @@ namespace Youshido\GraphQL\Execution\Visitor; - +use Exception; use Youshido\GraphQL\Config\Field\FieldConfig; class MaxComplexityQueryVisitor extends AbstractQueryVisitor { - /** - * @var int max score allowed before throwing an exception (causing processing to stop) + * @var ?int max score allowed before throwing an exception (causing processing to stop) */ - public $maxScore; + public ?int $maxScore; /** * @var int default score for nodes without explicit cost functions */ - protected $defaultScore = 1; + protected int $defaultScore = 1; /** * MaxComplexityQueryVisitor constructor. * - * @param int $max max allowed complexity score + * @param int|null $max max allowed complexity score */ - public function __construct($max) + public function __construct(?int $max) { parent::__construct(); @@ -41,10 +40,11 @@ public function __construct($max) /** * {@inheritdoc} + * @throws Exception */ public function visit(array $args, FieldConfig $fieldConfig, $childScore = 0) { - $cost = $fieldConfig->get('cost', null); + $cost = $fieldConfig->get('cost'); if (is_callable($cost)) { $cost = $cost($args, $fieldConfig, $childScore); } @@ -52,8 +52,8 @@ public function visit(array $args, FieldConfig $fieldConfig, $childScore = 0) $cost = is_null($cost) ? $this->defaultScore : $cost; $this->memo += $cost; - if ($this->memo > $this->maxScore) { - throw new \Exception('query exceeded max allowed complexity of ' . $this->maxScore); + if ($this->maxScore !== null && $this->maxScore !== 0 && $this->memo > $this->maxScore) { + throw new Exception('query exceeded max allowed complexity of ' . $this->maxScore); } return $cost; diff --git a/src/Field/AbstractField.php b/src/Field/AbstractField.php index 44a68d1f..62830fc8 100644 --- a/src/Field/AbstractField.php +++ b/src/Field/AbstractField.php @@ -9,8 +9,7 @@ use Youshido\GraphQL\Config\Field\FieldConfig; use Youshido\GraphQL\Config\Traits\ResolvableObjectTrait; -use Youshido\GraphQL\Type\AbstractType; -use Youshido\GraphQL\Type\Object\AbstractObjectType; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\Traits\AutoNameTrait; use Youshido\GraphQL\Type\Traits\FieldsArgumentsAwareObjectTrait; use Youshido\GraphQL\Type\TypeFactory; @@ -18,45 +17,48 @@ abstract class AbstractField implements FieldInterface { - use FieldsArgumentsAwareObjectTrait; use ResolvableObjectTrait; use AutoNameTrait { getName as getAutoName; } - protected $isFinal = false; - private $nameCache = null; + protected bool $isFinal = false; + + private mixed $nameCache = null; + /** + * @throws ConfigurationException + */ public function __construct(array $config = []) { if (empty($config['type'])) { $config['type'] = $this->getType(); $config['name'] = $this->getName(); if (empty($config['name'])) { - $config['name'] =$this->getAutoName(); + $config['name'] = $this->getAutoName(); } } if (TypeService::isScalarType($config['type'])) { $config['type'] = TypeFactory::getScalarType($config['type']); } - $this->nameCache = isset($config['name']) ? $config['name'] : $this->getAutoName(); + + if (!$this->nameCache) { + $this->nameCache = $config['name'] ?? $this->getAutoName(); + } $this->config = new FieldConfig($config, $this, $this->isFinal); $this->build($this->config); } - /** - * @return AbstractObjectType|AbstractType - */ - abstract public function getType(); + abstract public function getType(): mixed; - public function build(FieldConfig $config) + public function build(FieldConfig $config): void { } - public function setType($type) + public function setType($type): void { $this->getConfig()->set('type', $type); } diff --git a/src/Field/AbstractInputField.php b/src/Field/AbstractInputField.php index 110acec8..8529d0de 100644 --- a/src/Field/AbstractInputField.php +++ b/src/Field/AbstractInputField.php @@ -7,9 +7,9 @@ namespace Youshido\GraphQL\Field; - use Youshido\GraphQL\Config\Field\InputFieldConfig; -use Youshido\GraphQL\Type\InputTypeInterface; +use Youshido\GraphQL\Exception\ConfigurationException; +use Youshido\GraphQL\Type\AbstractType; use Youshido\GraphQL\Type\Traits\AutoNameTrait; use Youshido\GraphQL\Type\Traits\FieldsArgumentsAwareObjectTrait; use Youshido\GraphQL\Type\TypeFactory; @@ -18,10 +18,14 @@ abstract class AbstractInputField implements InputFieldInterface { - use FieldsArgumentsAwareObjectTrait, AutoNameTrait; + use FieldsArgumentsAwareObjectTrait; + use AutoNameTrait; - protected $isFinal = false; + protected bool $isFinal = false; + /** + * @throws ConfigurationException + */ public function __construct(array $config = []) { if (empty($config['type'])) { @@ -37,15 +41,12 @@ public function __construct(array $config = []) $this->build($this->config); } - public function build(InputFieldConfig $config) + public function build(InputFieldConfig $config): void { } - /** - * @return InputTypeInterface - */ - abstract public function getType(); + abstract public function getType(): mixed; public function getDefaultValue() { diff --git a/src/Field/Field.php b/src/Field/Field.php index fd63b289..736de423 100644 --- a/src/Field/Field.php +++ b/src/Field/Field.php @@ -7,8 +7,6 @@ namespace Youshido\GraphQL\Field; -use Youshido\GraphQL\Type\Object\AbstractObjectType; - /** * Class Field * @package Youshido\GraphQL\Type\Field @@ -17,22 +15,19 @@ final class Field extends AbstractField { - protected $isFinal = true; + protected bool $isFinal = true; + + protected $_typeCache; - protected $_typeCache = null; - protected $_nameCache = null; + protected $_nameCache; - /** - * @return AbstractObjectType - */ - public function getType() + public function getType(): mixed { - return $this->_typeCache ? $this->_typeCache : ($this->_typeCache = $this->getConfigValue('type')); + return $this->_typeCache ?: ($this->_typeCache = $this->getConfigValue('type')); } public function getName() { - return $this->_nameCache ? $this->_nameCache : ($this->_nameCache = $this->getConfigValue('name')); + return $this->_nameCache ?: ($this->_nameCache = $this->getConfigValue('name')); } - -} +} \ No newline at end of file diff --git a/src/Field/FieldInterface.php b/src/Field/FieldInterface.php index edaac4ba..fbe5945c 100644 --- a/src/Field/FieldInterface.php +++ b/src/Field/FieldInterface.php @@ -12,7 +12,7 @@ interface FieldInterface extends InputFieldInterface { - public function resolve($value, array $args, ResolveInfo $info); + public function resolve($value, array $args, ResolveInfo $info): mixed; - public function getResolveFunction(); + public function getResolveFunction(): ?callable; } diff --git a/src/Field/InputField.php b/src/Field/InputField.php index 5bf34b70..c0aed6e5 100644 --- a/src/Field/InputField.php +++ b/src/Field/InputField.php @@ -9,17 +9,12 @@ namespace Youshido\GraphQL\Field; -use Youshido\GraphQL\Type\Object\AbstractObjectType; - final class InputField extends AbstractInputField { - protected $isFinal = false; + protected bool $isFinal = false; - /** - * @return AbstractObjectType - */ - public function getType() + public function getType(): mixed { return $this->getConfigValue('type'); } diff --git a/src/Field/InputFieldInterface.php b/src/Field/InputFieldInterface.php index d658c15c..13c79d7f 100644 --- a/src/Field/InputFieldInterface.php +++ b/src/Field/InputFieldInterface.php @@ -13,10 +13,7 @@ interface InputFieldInterface { - /** - * @return AbstractType - */ - public function getType(); + public function getType(): mixed; public function getName(); @@ -29,26 +26,13 @@ public function addArgument($argument, $ArgumentInfo = null); /** * @return AbstractType[] */ - public function getArguments(); + public function getArguments(): array; - /** - * @param string $argumentName - * - * @return AbstractType - */ - public function getArgument($argumentName); + public function getArgument(string $argumentName); - /** - * @param string $argumentName - * - * @return bool - */ - public function hasArgument($argumentName); + public function hasArgument(string $argumentName): bool; - /** - * @return boolean - */ - public function hasArguments(); + public function hasArguments(): bool; } diff --git a/src/Introspection/DirectiveLocationType.php b/src/Introspection/DirectiveLocationType.php index d5b5e16f..8b2e3ba8 100644 --- a/src/Introspection/DirectiveLocationType.php +++ b/src/Introspection/DirectiveLocationType.php @@ -13,21 +13,28 @@ class DirectiveLocationType extends AbstractEnumType { - const QUERY = DirectiveLocation::QUERY; - const MUTATION = DirectiveLocation::MUTATION; - const FIELD = DirectiveLocation::FIELD; - const FIELD_DEFINITION = DirectiveLocation::FIELD_DEFINITION; - const FRAGMENT_DEFINITION = DirectiveLocation::FRAGMENT_DEFINITION; - const FRAGMENT_SPREAD = DirectiveLocation::FRAGMENT_SPREAD; - const INLINE_FRAGMENT = DirectiveLocation::INLINE_FRAGMENT; - const ENUM_VALUE = DirectiveLocation::ENUM_VALUE; - - public function getName() + final const QUERY = DirectiveLocation::QUERY; + + final const MUTATION = DirectiveLocation::MUTATION; + + final const FIELD = DirectiveLocation::FIELD; + + final const FIELD_DEFINITION = DirectiveLocation::FIELD_DEFINITION; + + final const FRAGMENT_DEFINITION = DirectiveLocation::FRAGMENT_DEFINITION; + + final const FRAGMENT_SPREAD = DirectiveLocation::FRAGMENT_SPREAD; + + final const INLINE_FRAGMENT = DirectiveLocation::INLINE_FRAGMENT; + + final const ENUM_VALUE = DirectiveLocation::ENUM_VALUE; + + public function getName(): string { return '__DirectiveLocation'; } - public function getValues() + public function getValues(): array { return [ ['name' => 'QUERY', 'value' => self::QUERY], diff --git a/src/Introspection/DirectiveType.php b/src/Introspection/DirectiveType.php index ba03632e..e4e49c1d 100644 --- a/src/Introspection/DirectiveType.php +++ b/src/Introspection/DirectiveType.php @@ -8,8 +8,9 @@ namespace Youshido\GraphQL\Introspection; use Youshido\GraphQL\Config\Directive\DirectiveConfig; -use Youshido\GraphQL\Directive\Directive; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Directive\DirectiveInterface; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\ListType\ListType; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; @@ -17,16 +18,15 @@ class DirectiveType extends AbstractObjectType { - /** * @return String type name */ - public function getName() + public function getName(): string { return '__Directive'; } - public function resolveArgs(DirectiveInterface $value) + public function resolveArgs(DirectiveInterface $value): array { if ($value->hasArguments()) { return $value->getArguments(); @@ -35,33 +35,29 @@ public function resolveArgs(DirectiveInterface $value) return []; } - /** - * @param DirectiveInterface|Directive $value - * - * @return mixed - */ - public function resolveLocations(DirectiveInterface $value) + public function resolveLocations(DirectiveInterface $value): mixed { /** @var DirectiveConfig $directiveConfig */ $directiveConfig = $value->getConfig(); - $locations = $directiveConfig->getLocations(); - - return $locations; + return $directiveConfig->getLocations(); } - public function build($config) + /** + * @throws ConfigurationException + */ + public function build(ObjectTypeConfig $config): void { $config ->addField('name', new NonNullType(TypeMap::TYPE_STRING)) ->addField('description', TypeMap::TYPE_STRING) ->addField('args', [ - 'type' => new NonNullType(new ListType(new NonNullType(new InputValueType()))), - 'resolve' => [$this, 'resolveArgs'], + 'type' => new NonNullType(new ListType(new NonNullType(new InputValueType()))), + 'resolve' => $this->resolveArgs(...), ]) - ->addField('locations',[ - 'type' => new NonNullType(new ListType(new NonNullType(new DirectiveLocationType()))), - 'resolve' => [$this, 'resolveLocations'], + ->addField('locations', [ + 'type' => new NonNullType(new ListType(new NonNullType(new DirectiveLocationType()))), + 'resolve' => $this->resolveLocations(...), ]); } } diff --git a/src/Introspection/EnumValueType.php b/src/Introspection/EnumValueType.php index 823b85af..bfa5902b 100644 --- a/src/Introspection/EnumValueType.php +++ b/src/Introspection/EnumValueType.php @@ -8,6 +8,8 @@ namespace Youshido\GraphQL\Introspection; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\TypeMap; @@ -15,7 +17,10 @@ class EnumValueType extends AbstractObjectType { - public function build($config) + /** + * @throws ConfigurationException + */ + public function build(ObjectTypeConfig $config): void { $config ->addField('name', new NonNullType(TypeMap::TYPE_STRING)) @@ -27,7 +32,7 @@ public function build($config) /** * @return String type name */ - public function getName() + public function getName(): string { return '__EnumValue'; } diff --git a/src/Introspection/Field/SchemaField.php b/src/Introspection/Field/SchemaField.php index 5febedde..f89f4fba 100644 --- a/src/Introspection/Field/SchemaField.php +++ b/src/Introspection/Field/SchemaField.php @@ -11,27 +11,21 @@ use Youshido\GraphQL\Execution\ResolveInfo; use Youshido\GraphQL\Field\AbstractField; use Youshido\GraphQL\Introspection\SchemaType; -use Youshido\GraphQL\Type\Object\AbstractObjectType; class SchemaField extends AbstractField { - /** - * @return AbstractObjectType - */ - public function getType() + public function getType(): SchemaType { return new SchemaType(); } - public function getName() + public function getName(): string { return '__schema'; } - public function resolve($value, array $args, ResolveInfo $info) + public function resolve($value, array $args, ResolveInfo $info): mixed { return $info->getExecutionContext()->getSchema(); } - - } diff --git a/src/Introspection/Field/TypeDefinitionField.php b/src/Introspection/Field/TypeDefinitionField.php index 4f0aae78..2c3e26ba 100644 --- a/src/Introspection/Field/TypeDefinitionField.php +++ b/src/Introspection/Field/TypeDefinitionField.php @@ -8,13 +8,13 @@ namespace Youshido\GraphQL\Introspection\Field; use Youshido\GraphQL\Config\Field\FieldConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Execution\ResolveInfo; use Youshido\GraphQL\Field\AbstractField; use Youshido\GraphQL\Field\InputField; use Youshido\GraphQL\Introspection\QueryType; use Youshido\GraphQL\Introspection\Traits\TypeCollectorTrait; use Youshido\GraphQL\Type\NonNullType; -use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Scalar\StringType; class TypeDefinitionField extends AbstractField @@ -22,7 +22,7 @@ class TypeDefinitionField extends AbstractField use TypeCollectorTrait; - public function resolve($value, array $args, ResolveInfo $info) + public function resolve($value, array $args, ResolveInfo $info): mixed { $schema = $info->getExecutionContext()->getSchema(); $this->collectTypes($schema->getQueryType()); @@ -41,7 +41,10 @@ public function resolve($value, array $args, ResolveInfo $info) return null; } - public function build(FieldConfig $config) + /** + * @throws ConfigurationException + */ + public function build(FieldConfig $config): void { $config->addArgument(new InputField([ 'name' => 'name', @@ -53,15 +56,12 @@ public function build(FieldConfig $config) /** * @return String type name */ - public function getName() + public function getName(): string { return '__type'; } - /** - * @return AbstractObjectType - */ - public function getType() + public function getType(): QueryType { return new QueryType(); } diff --git a/src/Introspection/Field/TypesField.php b/src/Introspection/Field/TypesField.php index c0130338..54b08b5b 100644 --- a/src/Introspection/Field/TypesField.php +++ b/src/Introspection/Field/TypesField.php @@ -8,6 +8,7 @@ namespace Youshido\GraphQL\Introspection\Field; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Execution\ResolveInfo; use Youshido\GraphQL\Field\AbstractField; use Youshido\GraphQL\Introspection\QueryType; @@ -23,18 +24,19 @@ class TypesField extends AbstractField /** * @return AbstractObjectType + * @throws ConfigurationException */ - public function getType() + public function getType(): ListType { return new ListType(new QueryType()); } - public function getName() + public function getName(): string { return 'types'; } - public function resolve($value, array $args, ResolveInfo $info) + public function resolve($value, array $args, ResolveInfo $info): array { /** @var $value AbstractSchema $a */ $this->types = []; @@ -45,7 +47,7 @@ public function resolve($value, array $args, ResolveInfo $info) } foreach ($value->getTypesList()->getTypes() as $type) { - $this->collectTypes($type); + $this->collectTypes($type); } return array_values($this->types); diff --git a/src/Introspection/FieldType.php b/src/Introspection/FieldType.php index 81458c68..a47e4c46 100644 --- a/src/Introspection/FieldType.php +++ b/src/Introspection/FieldType.php @@ -7,7 +7,10 @@ namespace Youshido\GraphQL\Introspection; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Field\FieldInterface; +use Youshido\GraphQL\Type\AbstractType; use Youshido\GraphQL\Type\ListType\ListType; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; @@ -16,12 +19,12 @@ class FieldType extends AbstractObjectType { - public function resolveType(FieldInterface $value) + public function resolveType(FieldInterface $value): AbstractType { return $value->getType(); } - public function resolveArgs(FieldInterface $value) + public function resolveArgs(FieldInterface $value): array { if ($value->hasArguments()) { return $value->getArguments(); @@ -30,7 +33,10 @@ public function resolveArgs(FieldInterface $value) return []; } - public function build($config) + /** + * @throws ConfigurationException + */ + public function build(ObjectTypeConfig $config): void { $config ->addField('name', new NonNullType(TypeMap::TYPE_STRING)) @@ -38,16 +44,16 @@ public function build($config) ->addField('isDeprecated', new NonNullType(TypeMap::TYPE_BOOLEAN)) ->addField('deprecationReason', TypeMap::TYPE_STRING) ->addField('type', [ - 'type' => new NonNullType(new QueryType()), - 'resolve' => [$this, 'resolveType'], + 'type' => new NonNullType(new QueryType()), + 'resolve' => $this->resolveType(...), ]) ->addField('args', [ - 'type' => new NonNullType(new ListType(new NonNullType(new InputValueType()))), - 'resolve' => [$this, 'resolveArgs'], + 'type' => new NonNullType(new ListType(new NonNullType(new InputValueType()))), + 'resolve' => $this->resolveArgs(...), ]); } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { return $value instanceof FieldInterface; } @@ -55,7 +61,7 @@ public function isValidValue($value) /** * @return String type name */ - public function getName() + public function getName(): string { return '__Field'; } diff --git a/src/Introspection/InputValueType.php b/src/Introspection/InputValueType.php index d2619a6a..a4e00ccc 100644 --- a/src/Introspection/InputValueType.php +++ b/src/Introspection/InputValueType.php @@ -7,7 +7,10 @@ namespace Youshido\GraphQL\Introspection; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Field\Field; +use Youshido\GraphQL\Field\InputField; use Youshido\GraphQL\Schema\AbstractSchema; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; @@ -16,30 +19,26 @@ class InputValueType extends AbstractObjectType { - /** - * @param AbstractSchema|Field $value - * - * @return TypeInterface - */ - public function resolveType($value) + public function resolveType(InputField|AbstractSchema|Field $value): TypeInterface { return $value->getConfig()->getType(); } /** - * @param AbstractSchema|Field $value - * - * @return string|null + * @return string|array|null * * //todo implement value printer */ - public function resolveDefaultValue($value) + public function resolveDefaultValue(InputField|AbstractSchema|Field $value): string|array|null { $resolvedValue = $value->getConfig()->getDefaultValue(); return $resolvedValue === null ? $resolvedValue : str_replace('"', '', json_encode($resolvedValue)); } - public function build($config) + /** + * @throws ConfigurationException + */ + public function build(ObjectTypeConfig $config): void { $config ->addField('name', new NonNullType(TypeMap::TYPE_STRING)) @@ -47,21 +46,21 @@ public function build($config) ->addField('isDeprecated', new NonNullType(TypeMap::TYPE_BOOLEAN)) ->addField('deprecationReason', TypeMap::TYPE_STRING) ->addField(new Field([ - 'name' => 'type', - 'type' => new NonNullType(new QueryType()), - 'resolve' => [$this, 'resolveType'] + 'name' => 'type', + 'type' => new NonNullType(new QueryType()), + 'resolve' => $this->resolveType(...) ])) ->addField('defaultValue', [ 'type' => TypeMap::TYPE_STRING, - 'resolve' => [$this, 'resolveDefaultValue'] + 'resolve' => $this->resolveDefaultValue(...) ]); } /** * @return string type name */ - public function getName() + public function getName(): string { return '__InputValue'; } -} +} \ No newline at end of file diff --git a/src/Introspection/QueryType.php b/src/Introspection/QueryType.php index 0de0bfc8..a4b80143 100644 --- a/src/Introspection/QueryType.php +++ b/src/Introspection/QueryType.php @@ -7,6 +7,8 @@ namespace Youshido\GraphQL\Introspection; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Execution\ResolveInfo; use Youshido\GraphQL\Field\Field; use Youshido\GraphQL\Introspection\Traits\TypeCollectorTrait; @@ -21,6 +23,7 @@ use Youshido\GraphQL\Type\Scalar\BooleanType; use Youshido\GraphQL\Type\TypeMap; use Youshido\GraphQL\Type\Union\AbstractUnionType; +use function array_unique; class QueryType extends AbstractObjectType { @@ -30,7 +33,7 @@ class QueryType extends AbstractObjectType /** * @return String type name */ - public function getName() + public function getName(): string { return '__Type'; } @@ -44,7 +47,7 @@ public function resolveOfType(AbstractType $value) return null; } - public function resolveInputFields($value) + public function resolveInputFields($value): ?array { if ($value instanceof AbstractInputObjectType) { /** @var AbstractObjectType $value */ @@ -54,22 +57,24 @@ public function resolveInputFields($value) return null; } - public function resolveEnumValues($value, $args) + public function resolveEnumValues($value, array $args): ?array { /** @var $value AbstractType|AbstractEnumType */ if ($value && $value->getKind() == TypeMap::KIND_ENUM) { $data = []; foreach ($value->getValues() as $enumValue) { - if(!$args['includeDeprecated'] && (isset($enumValue['isDeprecated']) && $enumValue['isDeprecated'])) { + if (!$args['includeDeprecated'] && (isset($enumValue['isDeprecated']) && $enumValue['isDeprecated'])) { continue; } if (!array_key_exists('description', $enumValue)) { $enumValue['description'] = ''; } + if (!array_key_exists('isDeprecated', $enumValue)) { $enumValue['isDeprecated'] = false; } + if (!array_key_exists('deprecationReason', $enumValue)) { $enumValue['deprecationReason'] = null; } @@ -83,7 +88,7 @@ public function resolveEnumValues($value, $args) return null; } - public function resolveFields($value, $args) + public function resolveFields($value, $args): ?array { /** @var AbstractType $value */ if (!$value || @@ -93,17 +98,13 @@ public function resolveFields($value, $args) } /** @var AbstractObjectType $value */ - return array_filter($value->getConfig()->getFields(), function ($field) use ($args) { + return array_filter($value->getConfig()->getFields(), static function ($field) use ($args): bool { /** @var $field Field */ - if (in_array($field->getName(), ['__type', '__schema']) || (!$args['includeDeprecated'] && $field->isDeprecated())) { - return false; - } - - return true; + return !in_array($field->getName(), ['__type', '__schema']) && !(!$args['includeDeprecated'] && $field->isDeprecated()); }); } - public function resolveInterfaces($value) + public function resolveInterfaces($value): array { /** @var $value AbstractType */ if ($value->getKind() == TypeMap::KIND_OBJECT) { @@ -111,17 +112,17 @@ public function resolveInterfaces($value) return $value->getConfig()->getInterfaces() ?: []; } - return null; + return []; } - public function resolvePossibleTypes($value, $args, ResolveInfo $info) + public function resolvePossibleTypes($value, $args, ResolveInfo $info): ?array { /** @var $value AbstractObjectType */ if ($value->getKind() == TypeMap::KIND_INTERFACE) { $schema = $info->getExecutionContext()->getSchema(); $this->collectTypes($schema->getQueryType()); foreach ($schema->getTypesList()->getTypes() as $type) { - $this->collectTypes($type); + $this->collectTypes($type); } $possibleTypes = []; @@ -146,7 +147,7 @@ public function resolvePossibleTypes($value, $args, ResolveInfo $info) } } - return \array_unique($possibleTypes); + return array_unique($possibleTypes); } elseif ($value->getKind() == TypeMap::KIND_UNION) { /** @var $value AbstractUnionType */ return $value->getTypes(); @@ -155,52 +156,60 @@ public function resolvePossibleTypes($value, $args, ResolveInfo $info) return null; } - public function build($config) + /** + * @throws ConfigurationException + */ + public function build(ObjectTypeConfig $config): void { $config ->addField('name', TypeMap::TYPE_STRING) ->addField('kind', new NonNullType(TypeMap::TYPE_STRING)) ->addField('description', TypeMap::TYPE_STRING) ->addField('ofType', [ - 'type' => new QueryType(), - 'resolve' => [$this, 'resolveOfType'] + 'type' => new QueryType(), + 'resolve' => $this->resolveOfType(...) ]) ->addField(new Field([ - 'name' => 'inputFields', - 'type' => new ListType(new NonNullType(new InputValueType())), - 'resolve' => [$this, 'resolveInputFields'] + 'name' => 'inputFields', + 'type' => new ListType(new NonNullType(new InputValueType())), + 'resolve' => $this->resolveInputFields(...) ])) ->addField(new Field([ - 'name' => 'enumValues', - 'args' => [ + 'name' => 'enumValues', + 'args' => [ 'includeDeprecated' => [ - 'type' => new BooleanType(), + 'type' => new BooleanType(), 'defaultValue' => false ] ], - 'type' => new ListType(new NonNullType(new EnumValueType())), - 'resolve' => [$this, 'resolveEnumValues'] + 'type' => new ListType(new NonNullType(new EnumValueType())), + 'resolve' => function ($value, array $args): ?array { + return $this->resolveEnumValues($value, $args); + } ])) ->addField(new Field([ - 'name' => 'fields', - 'args' => [ + 'name' => 'fields', + 'args' => [ 'includeDeprecated' => [ - 'type' => new BooleanType(), + 'type' => new BooleanType(), 'defaultValue' => false ] ], - 'type' => new ListType(new NonNullType(new FieldType())), - 'resolve' => [$this, 'resolveFields'] + 'type' => new ListType(new NonNullType(new FieldType())), + 'resolve' => function ($value, $args): ?array { + return $this->resolveFields($value, $args); + } ])) ->addField(new Field([ - 'name' => 'interfaces', - 'type' => new ListType(new NonNullType(new QueryType())), - 'resolve' => [$this, 'resolveInterfaces'] + 'name' => 'interfaces', + 'type' => new ListType(new NonNullType(new QueryType())), + 'resolve' => $this->resolveInterfaces(...) ])) ->addField('possibleTypes', [ - 'type' => new ListType(new NonNullType(new QueryType())), - 'resolve' => [$this, 'resolvePossibleTypes'] + 'type' => new ListType(new NonNullType(new QueryType())), + 'resolve' => function ($value, $args, ResolveInfo $info): ?array { + return $this->resolvePossibleTypes($value, $args, $info); + } ]); } - -} +} \ No newline at end of file diff --git a/src/Introspection/SchemaType.php b/src/Introspection/SchemaType.php index 3065a218..c3889e68 100644 --- a/src/Introspection/SchemaType.php +++ b/src/Introspection/SchemaType.php @@ -7,6 +7,8 @@ namespace Youshido\GraphQL\Introspection; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Field\Field; use Youshido\GraphQL\Introspection\Field\TypesField; use Youshido\GraphQL\Schema\AbstractSchema; @@ -19,7 +21,7 @@ class SchemaType extends AbstractObjectType /** * @return String type name */ - public function getName() + public function getName(): string { return '__Schema'; } @@ -41,36 +43,38 @@ public function resolveSubscriptionType() return null; } - public function resolveDirectives($value) + public function resolveDirectives($value): array { /** @var AbstractSchema|Field $value */ - $dirs = $value->getDirectiveList()->getDirectives(); - return $dirs; + return $value->getDirectiveList()->getDirectives(); } - public function build($config) + /** + * @throws ConfigurationException + */ + public function build(ObjectTypeConfig $config): void { $config ->addField(new Field([ - 'name' => 'queryType', - 'type' => new QueryType(), - 'resolve' => [$this, 'resolveQueryType'] + 'name' => 'queryType', + 'type' => new QueryType(), + 'resolve' => $this->resolveQueryType(...) ])) ->addField(new Field([ - 'name' => 'mutationType', - 'type' => new QueryType(), - 'resolve' => [$this, 'resolveMutationType'] + 'name' => 'mutationType', + 'type' => new QueryType(), + 'resolve' => $this->resolveMutationType(...) ])) ->addField(new Field([ - 'name' => 'subscriptionType', - 'type' => new QueryType(), - 'resolve' => [$this, 'resolveSubscriptionType'] + 'name' => 'subscriptionType', + 'type' => new QueryType(), + 'resolve' => $this->resolveSubscriptionType(...) ])) ->addField(new TypesField()) ->addField(new Field([ - 'name' => 'directives', - 'type' => new ListType(new DirectiveType()), - 'resolve' => [$this, 'resolveDirectives'] + 'name' => 'directives', + 'type' => new ListType(new DirectiveType()), + 'resolve' => $this->resolveDirectives(...) ])); } } diff --git a/src/Introspection/Traits/TypeCollectorTrait.php b/src/Introspection/Traits/TypeCollectorTrait.php index 7390285c..7d4ee4a0 100644 --- a/src/Introspection/Traits/TypeCollectorTrait.php +++ b/src/Introspection/Traits/TypeCollectorTrait.php @@ -8,6 +8,7 @@ namespace Youshido\GraphQL\Introspection\Traits; use Youshido\GraphQL\Type\AbstractType; +use Youshido\GraphQL\Type\InputObject\AbstractInputObjectType; use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\TypeMap; @@ -15,12 +16,13 @@ trait TypeCollectorTrait { + protected array $types = []; - protected $types = []; - - protected function collectTypes(AbstractType $type) + protected function collectTypes(?AbstractType $type): void { - if (is_object($type) && array_key_exists($type->getName(), $this->types)) return; + if (!$type instanceof AbstractType || array_key_exists($type->getName(), $this->types)) { + return; + } switch ($type->getKind()) { case TypeMap::KIND_INTERFACE: @@ -29,7 +31,7 @@ protected function collectTypes(AbstractType $type) case TypeMap::KIND_SCALAR: $this->insertType($type->getName(), $type); - if ($type->getKind() == TypeMap::KIND_UNION) { + if ($type->getKind() === TypeMap::KIND_UNION) { /** @var AbstractUnionType $type */ foreach ($type->getTypes() as $subType) { $this->collectTypes($subType); @@ -51,8 +53,6 @@ protected function collectTypes(AbstractType $type) break; case TypeMap::KIND_LIST: - $this->collectTypes($type->getNamedType()); - break; case TypeMap::KIND_NON_NULL: $this->collectTypes($type->getNamedType()); @@ -61,7 +61,7 @@ protected function collectTypes(AbstractType $type) } } - private function checkAndInsertInterfaces($type) + private function checkAndInsertInterfaces($type): void { foreach ((array)$type->getConfig()->getInterfaces() as $interface) { $this->insertType($interface->getName(), $interface); @@ -74,10 +74,7 @@ private function checkAndInsertInterfaces($type) } } - /** - * @param $type AbstractObjectType - */ - private function collectFieldsArgsTypes($type) + private function collectFieldsArgsTypes(AbstractObjectType|AbstractInputObjectType $type): void { foreach ($type->getConfig()->getFields() as $field) { $arguments = $field->getConfig()->getArguments(); @@ -92,7 +89,7 @@ private function collectFieldsArgsTypes($type) } } - private function insertType($name, $type) + private function insertType($name, $type): bool { if (!array_key_exists($name, $this->types)) { $this->types[$name] = $type; @@ -102,5 +99,4 @@ private function insertType($name, $type) return false; } - } diff --git a/src/Parser/Ast/AbstractAst.php b/src/Parser/Ast/AbstractAst.php index 7f7dce3d..e9fc2a7d 100644 --- a/src/Parser/Ast/AbstractAst.php +++ b/src/Parser/Ast/AbstractAst.php @@ -14,8 +14,7 @@ abstract class AbstractAst implements LocatableInterface { - /** @var Location */ - private $location; + private Location $location; public function __construct(Location $location) { @@ -27,7 +26,7 @@ public function getLocation() return $this->location; } - public function setLocation(Location $location) + public function setLocation(Location $location): void { $this->location = $location; } diff --git a/src/Parser/Ast/Argument.php b/src/Parser/Ast/Argument.php index bb0aa8af..f31c2f59 100644 --- a/src/Parser/Ast/Argument.php +++ b/src/Parser/Ast/Argument.php @@ -7,63 +7,46 @@ namespace Youshido\GraphQL\Parser\Ast; - use Youshido\GraphQL\Parser\Ast\Interfaces\ValueInterface; use Youshido\GraphQL\Parser\Location; -class Argument extends AbstractAst +class Argument extends AbstractAst implements ValueInterface { + private string $name; - /** @var string */ - private $name; - - /** @var ValueInterface */ - private $value; + /** + * TODO - Was ValueInterface - is there any reason for that? + */ + private mixed $value; /** - * @param string $name - * @param ValueInterface $value - * @param Location $location + * @param string $name */ - public function __construct($name, ValueInterface $value, Location $location) + public function __construct($name, $value, Location $location) { parent::__construct($location); - $this->name = $name; + $this->name = $name; $this->value = $value; } - /** - * @return mixed - */ - public function getName() + public function getName(): string { return $this->name; } - /** - * @param mixed $name - */ - public function setName($name) + public function setName(string $name): void { $this->name = $name; } - /** - * @return \Youshido\GraphQL\Parser\Ast\Interfaces\ValueInterface - */ - public function getValue() + public function getValue(): mixed { return $this->value; } - /** - * @param mixed $value - */ - public function setValue($value) + public function setValue(mixed $value): void { $this->value = $value; } - - } \ No newline at end of file diff --git a/src/Parser/Ast/ArgumentValue/InputList.php b/src/Parser/Ast/ArgumentValue/InputList.php index 03867885..4c3b7247 100644 --- a/src/Parser/Ast/ArgumentValue/InputList.php +++ b/src/Parser/Ast/ArgumentValue/InputList.php @@ -15,12 +15,8 @@ class InputList extends AbstractAst implements ValueInterface { - protected $list = []; + protected array $list; - /** - * @param array $list - * @param Location $location - */ public function __construct(array $list, Location $location) { parent::__construct($location); @@ -28,10 +24,7 @@ public function __construct(array $list, Location $location) $this->list = $list; } - /** - * @return array - */ - public function getValue() + public function getValue(): array { return $this->list; } @@ -39,7 +32,7 @@ public function getValue() /** * @param array $value */ - public function setValue($value) + public function setValue($value): void { $this->list = $value; } diff --git a/src/Parser/Ast/ArgumentValue/InputObject.php b/src/Parser/Ast/ArgumentValue/InputObject.php index 92b34144..7b900ab6 100644 --- a/src/Parser/Ast/ArgumentValue/InputObject.php +++ b/src/Parser/Ast/ArgumentValue/InputObject.php @@ -15,12 +15,8 @@ class InputObject extends AbstractAst implements ValueInterface { - protected $object = []; + protected array $object; - /** - * @param array $object - * @param Location $location - */ public function __construct(array $object, Location $location) { parent::__construct($location); @@ -28,10 +24,7 @@ public function __construct(array $object, Location $location) $this->object = $object; } - /** - * @return array - */ - public function getValue() + public function getValue(): array { return $this->object; } @@ -39,7 +32,7 @@ public function getValue() /** * @param array $value */ - public function setValue($value) + public function setValue($value): void { $this->object = $value; } diff --git a/src/Parser/Ast/ArgumentValue/Literal.php b/src/Parser/Ast/ArgumentValue/Literal.php index dabd6319..9b885745 100644 --- a/src/Parser/Ast/ArgumentValue/Literal.php +++ b/src/Parser/Ast/ArgumentValue/Literal.php @@ -19,7 +19,6 @@ class Literal extends AbstractAst implements ValueInterface /** * @param mixed $value - * @param Location $location */ public function __construct($value, Location $location) { @@ -36,7 +35,7 @@ public function getValue() /** * @param string $value */ - public function setValue($value) + public function setValue($value): void { $this->value = $value; } diff --git a/src/Parser/Ast/ArgumentValue/Variable.php b/src/Parser/Ast/ArgumentValue/Variable.php index 63b9d01d..01203d89 100644 --- a/src/Parser/Ast/ArgumentValue/Variable.php +++ b/src/Parser/Ast/ArgumentValue/Variable.php @@ -7,6 +7,7 @@ namespace Youshido\GraphQL\Parser\Ast\ArgumentValue; +use LogicException; use Youshido\GraphQL\Parser\Ast\AbstractAst; use Youshido\GraphQL\Parser\Ast\Interfaces\ValueInterface; use Youshido\GraphQL\Parser\Location; @@ -23,47 +24,41 @@ class Variable extends AbstractAst implements ValueInterface /** @var string */ private $type; - /** @var bool */ - private $nullable = false; + private bool $nullable = false; - /** @var bool */ - private $isArray = false; + private bool $isArray = false; - /** @var bool */ - private $used = false; + private bool $used = false; - /** @var bool */ - private $arrayElementNullable = true; + private bool $arrayElementNullable = true; - /** @var bool */ - private $hasDefaultValue = false; + private bool $hasDefaultValue = false; /** @var mixed */ - private $defaultValue = null; + private $defaultValue; /** - * @param string $name - * @param string $type - * @param bool $nullable - * @param bool $isArray - * @param bool $arrayElementNullable - * @param Location $location + * @param string $name + * @param string $type + * @param bool $nullable + * @param bool $isArray + * @param bool $arrayElementNullable */ - public function __construct($name, $type, $nullable, $isArray, $arrayElementNullable = true, Location $location) + public function __construct($name, $type, $nullable, $isArray, Location $location, $arrayElementNullable = true) { parent::__construct($location); - $this->name = $name; - $this->type = $type; - $this->isArray = $isArray; - $this->nullable = $nullable; + $this->name = $name; + $this->type = $type; + $this->isArray = $isArray; + $this->nullable = $nullable; $this->arrayElementNullable = $arrayElementNullable; } /** * @return mixed * - * @throws \LogicException + * @throws LogicException */ public function getValue() { @@ -71,7 +66,8 @@ public function getValue() if ($this->hasDefaultValue()) { return $this->defaultValue; } - throw new \LogicException('Value is not set for variable "' . $this->name . '"'); + + throw new LogicException('Value is not set for variable "' . $this->name . '"'); } return $this->value; @@ -80,7 +76,7 @@ public function getValue() /** * @param mixed $value */ - public function setValue($value) + public function setValue($value): void { $this->value = $value; } @@ -96,7 +92,7 @@ public function getName() /** * @param string $name */ - public function setName($name) + public function setName($name): void { $this->name = $name; } @@ -112,47 +108,32 @@ public function getTypeName() /** * @param string $type */ - public function setTypeName($type) + public function setTypeName($type): void { $this->type = $type; } - /** - * @return boolean - */ - public function isArray() + public function isArray(): bool { return $this->isArray; } - /** - * @param boolean $isArray - */ - public function setIsArray($isArray) + public function setIsArray(bool $isArray): void { $this->isArray = $isArray; } - /** - * @return boolean - */ - public function isNullable() + public function isNullable(): bool { return $this->nullable; } - /** - * @param boolean $nullable - */ - public function setNullable($nullable) + public function setNullable(bool $nullable): void { $this->nullable = $nullable; } - /** - * @return bool - */ - public function hasDefaultValue() + public function hasDefaultValue(): bool { return $this->hasDefaultValue; } @@ -168,45 +149,34 @@ public function getDefaultValue() /** * @param mixed $defaultValue */ - public function setDefaultValue($defaultValue) + public function setDefaultValue($defaultValue): void { $this->hasDefaultValue = true; $this->defaultValue = $defaultValue; } - /** - * @return boolean - */ - public function isUsed() + public function isUsed(): bool { return $this->used; } /** - * @param boolean $used - * * @return $this */ - public function setUsed($used) + public function setUsed(bool $used): static { $this->used = $used; return $this; } - /** - * @return bool - */ - public function isArrayElementNullable() + public function isArrayElementNullable(): bool { return $this->arrayElementNullable; } - /** - * @param bool $arrayElementNullable - */ - public function setArrayElementNullable($arrayElementNullable) + public function setArrayElementNullable(bool $arrayElementNullable): void { $this->arrayElementNullable = $arrayElementNullable; } diff --git a/src/Parser/Ast/ArgumentValue/VariableReference.php b/src/Parser/Ast/ArgumentValue/VariableReference.php index c754db1d..dac879cb 100644 --- a/src/Parser/Ast/ArgumentValue/VariableReference.php +++ b/src/Parser/Ast/ArgumentValue/VariableReference.php @@ -18,26 +18,24 @@ class VariableReference extends AbstractAst implements ValueInterface /** @var string */ private $name; - /** @var Variable */ - private $variable; + private readonly ?Variable $variable; /** @var mixed */ private $value; /** - * @param string $name + * @param string $name * @param Variable|null $variable - * @param Location $location */ - public function __construct($name, Variable $variable = null, Location $location) + public function __construct($name, Location $location, ?Variable $variable = null) { parent::__construct($location); - $this->name = $name; + $this->name = $name; $this->variable = $variable; } - public function getVariable() + public function getVariable(): ?Variable { return $this->variable; } @@ -47,7 +45,7 @@ public function getValue() return $this->value; } - public function setValue($value) + public function setValue($value): void { $this->value = $value; } diff --git a/src/Parser/Ast/AstArgumentsTrait.php b/src/Parser/Ast/AstArgumentsTrait.php index b572b3a7..dfe38bf7 100644 --- a/src/Parser/Ast/AstArgumentsTrait.php +++ b/src/Parser/Ast/AstArgumentsTrait.php @@ -13,17 +13,17 @@ trait AstArgumentsTrait { /** @var Argument[] */ - protected $arguments; + protected array $arguments; - private $argumentsCache = null; + private $argumentsCache; - public function hasArguments() + public function hasArguments(): bool { return (bool)count($this->arguments); } - public function hasArgument($name) + public function hasArgument($name): bool { return array_key_exists($name, $this->arguments); } @@ -31,17 +31,12 @@ public function hasArgument($name) /** * @return Argument[] */ - public function getArguments() + public function getArguments(): array { return $this->arguments; } - /** - * @param $name - * - * @return null|Argument - */ - public function getArgument($name) + public function getArgument(string $name): ?Argument { $argument = null; if (isset($this->arguments[$name])) { @@ -55,13 +50,13 @@ public function getArgumentValue($name) { $argument = $this->getArgument($name); - return $argument ? $argument->getValue()->getValue() : null; + return $argument?->getValue()->getValue(); } /** * @param $arguments Argument[] */ - public function setArguments(array $arguments) + public function setArguments(array $arguments): void { $this->arguments = []; $this->argumentsCache = null; @@ -71,12 +66,12 @@ public function setArguments(array $arguments) } } - public function addArgument(Argument $argument) + public function addArgument(Argument $argument): void { $this->arguments[$argument->getName()] = $argument; } - public function getKeyValueArguments() + public function getKeyValueArguments(): array { if ($this->argumentsCache !== null) { return $this->argumentsCache; diff --git a/src/Parser/Ast/AstDirectivesTrait.php b/src/Parser/Ast/AstDirectivesTrait.php index a4b37004..914fab4d 100644 --- a/src/Parser/Ast/AstDirectivesTrait.php +++ b/src/Parser/Ast/AstDirectivesTrait.php @@ -14,15 +14,15 @@ trait AstDirectivesTrait /** @var Directive[] */ protected $directives; - private $directivesCache = null; + private $directivesCache; - public function hasDirectives() + public function hasDirectives(): bool { return (bool)count($this->directives); } - public function hasDirective($name) + public function hasDirective($name): bool { return array_key_exists($name, $this->directives); } @@ -53,9 +53,9 @@ public function getDirectives() /** * @param $directives Directive[] */ - public function setDirectives(array $directives) + public function setDirectives(array $directives): void { - $this->directives = []; + $this->directives = []; $this->directivesCache = null; foreach ($directives as $directive) { @@ -63,7 +63,7 @@ public function setDirectives(array $directives) } } - public function addDirective(Directive $directive) + public function addDirective(Directive $directive): void { $this->directives[$directive->getName()] = $directive; } diff --git a/src/Parser/Ast/Directive.php b/src/Parser/Ast/Directive.php index 9f66549b..647c6912 100644 --- a/src/Parser/Ast/Directive.php +++ b/src/Parser/Ast/Directive.php @@ -19,9 +19,7 @@ class Directive extends AbstractAst /** - * @param string $name - * @param array $arguments - * @param Location $location + * @param string $name */ public function __construct($name, array $arguments, Location $location) { @@ -42,7 +40,7 @@ public function getName() /** * @param mixed $name */ - public function setName($name) + public function setName($name): void { $this->name = $name; } diff --git a/src/Parser/Ast/Field.php b/src/Parser/Ast/Field.php index 5036a171..fa8f2809 100644 --- a/src/Parser/Ast/Field.php +++ b/src/Parser/Ast/Field.php @@ -16,67 +16,50 @@ class Field extends AbstractAst implements FieldInterface use AstArgumentsTrait; use AstDirectivesTrait; - /** @var string */ - private $name; + private ?string $name; - /** @var string */ - private $alias; + private ?string $alias; /** - * @param string $name - * @param string $alias - * @param array $arguments - * @param array $directives - * @param Location $location + * @param string $name + * @param string $alias */ public function __construct($name, $alias, array $arguments, array $directives, Location $location) { parent::__construct($location); - $this->name = $name; - $this->alias = $alias; + $this->name = $name; + $this->alias = $alias; $this->setArguments($arguments); $this->setDirectives($directives); } - /** - * @return string - */ - public function getName() + public function getName(): string { return $this->name; } - /** - * @param string $name - */ - public function setName($name) + public function setName(string $name): void { $this->name = $name; } - /** - * @return null|string - */ - public function getAlias() + public function getAlias(): ?string { return $this->alias; } - /** - * @param null|string $alias - */ - public function setAlias($alias) + public function setAlias(?string $alias): void { $this->alias = $alias; } - public function hasFields() + public function hasFields(): bool { return false; } - public function getFields() + public function getFields(): array { return []; } diff --git a/src/Parser/Ast/Fragment.php b/src/Parser/Ast/Fragment.php index 7ea8b142..3b10ad36 100644 --- a/src/Parser/Ast/Fragment.php +++ b/src/Parser/Ast/Fragment.php @@ -20,40 +20,31 @@ class Fragment extends AbstractAst protected $model; /** @var Field[]|Query[] */ - protected $fields; + protected array $fields; - /** @var bool */ - private $used = false; + private bool $used = false; /** - * @param string $name - * @param string $model - * @param array $directives + * @param string $name + * @param string $model * @param Field[]|Query[] $fields - * @param Location $location */ public function __construct($name, $model, array $directives, array $fields, Location $location) { parent::__construct($location); - $this->name = $name; - $this->model = $model; + $this->name = $name; + $this->model = $model; $this->fields = $fields; $this->setDirectives($directives); } - /** - * @return boolean - */ - public function isUsed() + public function isUsed(): bool { return $this->used; } - /** - * @param boolean $used - */ - public function setUsed($used) + public function setUsed(bool $used): void { $this->used = $used; } @@ -69,7 +60,7 @@ public function getName() /** * @param mixed $name */ - public function setName($name) + public function setName($name): void { $this->name = $name; } @@ -85,7 +76,7 @@ public function getModel() /** * @param mixed $model */ - public function setModel($model) + public function setModel($model): void { $this->model = $model; } @@ -93,7 +84,7 @@ public function setModel($model) /** * @return Field[]|Query[] */ - public function getFields() + public function getFields(): array { return $this->fields; } @@ -101,7 +92,7 @@ public function getFields() /** * @param Field[]|Query[] $fields */ - public function setFields($fields) + public function setFields(array $fields): void { $this->fields = $fields; } diff --git a/src/Parser/Ast/FragmentReference.php b/src/Parser/Ast/FragmentReference.php index 1fa01083..87f9ff38 100644 --- a/src/Parser/Ast/FragmentReference.php +++ b/src/Parser/Ast/FragmentReference.php @@ -18,8 +18,7 @@ class FragmentReference extends AbstractAst implements FragmentInterface protected $name; /** - * @param string $name - * @param Location $location + * @param string $name */ public function __construct($name, Location $location) { @@ -39,7 +38,7 @@ public function getName() /** * @param string $name */ - public function setName($name) + public function setName($name): void { $this->name = $name; } diff --git a/src/Parser/Ast/Interfaces/FieldInterface.php b/src/Parser/Ast/Interfaces/FieldInterface.php index 2bc94bed..2737e913 100644 --- a/src/Parser/Ast/Interfaces/FieldInterface.php +++ b/src/Parser/Ast/Interfaces/FieldInterface.php @@ -12,37 +12,19 @@ interface FieldInterface extends LocatableInterface { + public function getName(): string; - /** - * @return string - */ - public function getName(); - - /** - * @return string - */ - public function getAlias(); + public function getAlias(): ?string; /** * @return Argument[] */ - public function getArguments(); + public function getArguments(): array; - /** - * @param string $name - * - * @return Argument - */ - public function getArgument($name); + public function getArgument(string $name); - /** - * @return bool - */ - public function hasFields(); + public function hasFields(): bool; - /** - * @return array - */ - public function getFields(); + public function getFields(): array; } diff --git a/src/Parser/Ast/Query.php b/src/Parser/Ast/Query.php index 2feecd29..c6d31b4b 100644 --- a/src/Parser/Ast/Query.php +++ b/src/Parser/Ast/Query.php @@ -29,25 +29,21 @@ class Query extends AbstractAst implements FieldInterface /** * Query constructor. * - * @param string $name - * @param string $alias - * @param array $arguments - * @param array $fields - * @param array $directives - * @param Location $location + * @param string $name + * @param string $alias */ public function __construct($name, $alias, array $arguments, array $fields, array $directives, Location $location) { parent::__construct($location); - $this->name = $name; - $this->alias = $alias; + $this->name = $name; + $this->alias = $alias; $this->setFields($fields); $this->setArguments($arguments); $this->setDirectives($directives); } - public function getName() + public function getName(): string { return $this->name; } @@ -55,15 +51,12 @@ public function getName() /** * @return Field[]|Query[]|FragmentInterface[] */ - public function getFields() + public function getFields(): array { return array_values($this->fields); } - /** - * @return bool - */ - public function hasFields() + public function hasFields(): bool { return (bool)count($this->fields); } @@ -71,30 +64,28 @@ public function hasFields() /** * @param Field[]|Query[] $fields */ - public function setFields($fields) + public function setFields($fields): void { /** * we cannot store fields by name because of TypedFragments */ $this->fields = $fields; - } + } - public function getAlias() + public function getAlias(): ?string { return $this->alias; } - public function hasField($name, $deep = false) + public function hasField($name, $deep = false): bool { foreach ($this->getFields() as $field) { if ($field->getName() == $name) { return true; } - if ($deep && $field instanceof Query) { - if ($field->hasField($name)) { - return true; - } + if ($deep && $field instanceof Query && $field->hasField($name)) { + return true; } } diff --git a/src/Parser/Ast/TypedFragmentReference.php b/src/Parser/Ast/TypedFragmentReference.php index 749c6bbe..987dd99a 100644 --- a/src/Parser/Ast/TypedFragmentReference.php +++ b/src/Parser/Ast/TypedFragmentReference.php @@ -16,30 +16,29 @@ class TypedFragmentReference extends AbstractAst implements FragmentInterface use AstDirectivesTrait; /** @var Field[]|Query[] */ - protected $fields; + protected array $fields; /** @var string */ protected $typeName; /** - * @param string $typeName + * @param string $typeName * @param Field[]|Query[] $fields - * @param Directive[] $directives - * @param Location $location + * @param Directive[] $directives */ public function __construct($typeName, array $fields, array $directives, Location $location) { parent::__construct($location); $this->typeName = $typeName; - $this->fields = $fields; + $this->fields = $fields; $this->setDirectives($directives); } /** * @return Field[]|Query[] */ - public function getFields() + public function getFields(): array { return $this->fields; } @@ -47,7 +46,7 @@ public function getFields() /** * @param Field[]|Query[] $fields */ - public function setFields($fields) + public function setFields(array $fields): void { $this->fields = $fields; } @@ -63,7 +62,7 @@ public function getTypeName() /** * @param string $typeName */ - public function setTypeName($typeName) + public function setTypeName($typeName): void { $this->typeName = $typeName; } diff --git a/src/Parser/Location.php b/src/Parser/Location.php index adb5cf20..dd514e96 100644 --- a/src/Parser/Location.php +++ b/src/Parser/Location.php @@ -19,7 +19,7 @@ class Location public function __construct($line, $column) { - $this->line = $line; + $this->line = $line; $this->column = $column; } @@ -40,10 +40,10 @@ public function getColumn() } - public function toArray() + public function toArray(): array { return [ - 'line' => $this->getLine(), + 'line' => $this->getLine(), 'column' => $this->getColumn() ]; } diff --git a/src/Parser/Parser.php b/src/Parser/Parser.php index d3dad3cc..b289f9c4 100644 --- a/src/Parser/Parser.php +++ b/src/Parser/Parser.php @@ -27,10 +27,12 @@ class Parser extends Tokenizer { - /** @var array */ - private $data = []; + private array $data = []; - public function parse($source = null) + /** + * @throws SyntaxErrorException + */ + public function parse($source = null): array { $this->init($source); @@ -45,7 +47,7 @@ public function parse($source = null) break; case Token::TYPE_QUERY: - $queries = $this->parseOperation(Token::TYPE_QUERY); + $queries = $this->parseOperation(); foreach ($queries as $query) { $this->data['queries'][] = $query; } @@ -72,23 +74,28 @@ public function parse($source = null) return $this->data; } - private function init($source = null) + private function init($source = null): void { $this->initTokenizer($source); $this->data = [ - 'queries' => [], - 'mutations' => [], - 'fragments' => [], + 'queries' => [], + 'mutations' => [], + 'fragments' => [], 'fragmentReferences' => [], - 'variables' => [], + 'variables' => [], 'variableReferences' => [], ]; } - protected function parseOperation($type = Token::TYPE_QUERY) + /** + * @return mixed[] + * @throws SyntaxErrorException + * @throws SyntaxErrorException + */ + protected function parseOperation($type = Token::TYPE_QUERY): array { - $operation = null; + $operation = null; $directives = []; if ($this->matchMulti([Token::TYPE_QUERY, Token::TYPE_MUTATION])) { @@ -113,7 +120,7 @@ protected function parseOperation($type = Token::TYPE_QUERY) while (!$this->match(Token::TYPE_RBRACE) && !$this->end()) { $this->eatMulti([Token::TYPE_COMMA]); - $operation = $this->parseBodyItem($type, true); + $operation = $this->parseBodyItem($type); $operation->setDirectives($directives); $fields[] = $operation; @@ -124,7 +131,13 @@ protected function parseOperation($type = Token::TYPE_QUERY) return $fields; } - protected function parseBody($token = Token::TYPE_QUERY, $highLevel = true) + /** + * @return mixed[] + * @throws SyntaxErrorException + * @throws SyntaxErrorException + * @throws SyntaxErrorException + */ + protected function parseBody($token = Token::TYPE_QUERY, $highLevel = true): array { $fields = []; @@ -151,6 +164,9 @@ protected function parseBody($token = Token::TYPE_QUERY, $highLevel = true) return $fields; } + /** + * @throws SyntaxErrorException + */ protected function parseVariables() { $this->eat(Token::TYPE_LPAREN); @@ -159,10 +175,10 @@ protected function parseVariables() $this->eat(Token::TYPE_COMMA); $variableToken = $this->eat(Token::TYPE_VARIABLE); - $nameToken = $this->eatIdentifierToken(); + $nameToken = $this->eatIdentifierToken(); $this->eat(Token::TYPE_COLON); - $isArray = false; + $isArray = false; $arrayElementNullable = true; if ($this->match(Token::TYPE_LSQUARE_BRACE)) { @@ -192,8 +208,8 @@ protected function parseVariables() $type, $required, $isArray, - $arrayElementNullable, - new Location($variableToken->getLine(), $variableToken->getColumn()) + new Location($variableToken->getLine(), $variableToken->getColumn()), + $arrayElementNullable ); if ($this->match(Token::TYPE_EQUAL)) { @@ -207,6 +223,9 @@ protected function parseVariables() $this->expect(Token::TYPE_RPAREN); } + /** + * @throws SyntaxErrorException + */ protected function expectMulti($types) { if ($this->matchMulti($types)) { @@ -216,6 +235,9 @@ protected function expectMulti($types) throw $this->createUnexpectedException($this->peek()); } + /** + * @throws SyntaxErrorException + */ protected function parseVariableReference() { $startToken = $this->expectMulti([Token::TYPE_VARIABLE]); @@ -224,11 +246,9 @@ protected function parseVariableReference() $name = $this->lex()->getData(); $variable = $this->findVariable($name); - if ($variable) { - $variable->setUsed(true); - } + $variable?->setUsed(true); - $variableReference = new VariableReference($name, $variable, new Location($startToken->getLine(), $startToken->getColumn())); + $variableReference = new VariableReference($name, new Location($startToken->getLine(), $startToken->getColumn()), $variable); $this->data['variableReferences'][] = $variableReference; @@ -240,7 +260,7 @@ protected function parseVariableReference() protected function findVariable($name) { - foreach ((array) $this->data['variables'] as $variable) { + foreach ((array)$this->data['variables'] as $variable) { /** @var $variable Variable */ if ($variable->getName() === $name) { return $variable; @@ -250,9 +270,9 @@ protected function findVariable($name) return null; } - protected function parseFragmentReference() + protected function parseFragmentReference(): FragmentReference { - $nameToken = $this->eatIdentifierToken(); + $nameToken = $this->eatIdentifierToken(); $fragmentReference = new FragmentReference($nameToken->getData(), new Location($nameToken->getLine(), $nameToken->getColumn())); $this->data['fragmentReferences'][] = $fragmentReference; @@ -260,6 +280,9 @@ protected function parseFragmentReference() return $fragmentReference; } + /** + * @throws SyntaxErrorException + */ protected function eatIdentifierToken() { return $this->expectMulti([ @@ -270,24 +293,27 @@ protected function eatIdentifierToken() ]); } - protected function parseBodyItem($type = Token::TYPE_QUERY, $highLevel = true) + /** + * @throws SyntaxErrorException + */ + protected function parseBodyItem($type = Token::TYPE_QUERY, $highLevel = true): Query|TypedFragmentReference|Mutation|Field { $nameToken = $this->eatIdentifierToken(); - $alias = null; + $alias = null; if ($this->eat(Token::TYPE_COLON)) { - $alias = $nameToken->getData(); + $alias = $nameToken->getData(); $nameToken = $this->eatIdentifierToken(); } $bodyLocation = new Location($nameToken->getLine(), $nameToken->getColumn()); - $arguments = $this->match(Token::TYPE_LPAREN) ? $this->parseArgumentList() : []; - $directives = $this->match(Token::TYPE_AT) ? $this->parseDirectiveList() : []; + $arguments = $this->match(Token::TYPE_LPAREN) ? $this->parseArgumentList() : []; + $directives = $this->match(Token::TYPE_AT) ? $this->parseDirectiveList() : []; if ($this->match(Token::TYPE_LBRACE)) { $fields = $this->parseBody($type === Token::TYPE_TYPED_FRAGMENT ? Token::TYPE_QUERY : $type, false); - if (!$fields) { + if ($fields === []) { throw $this->createUnexpectedTokenTypeException($this->lookAhead->getType()); } @@ -309,7 +335,12 @@ protected function parseBodyItem($type = Token::TYPE_QUERY, $highLevel = true) } } - protected function parseArgumentList() + /** + * @return mixed[] + * @throws SyntaxErrorException + * @throws SyntaxErrorException + */ + protected function parseArgumentList(): array { $args = []; @@ -325,7 +356,10 @@ protected function parseArgumentList() return $args; } - protected function parseArgument() + /** + * @throws SyntaxErrorException + */ + protected function parseArgument(): Argument { $nameToken = $this->eatIdentifierToken(); $this->expect(Token::TYPE_COLON); @@ -334,7 +368,10 @@ protected function parseArgument() return new Argument($nameToken->getData(), $value, new Location($nameToken->getLine(), $nameToken->getColumn())); } - protected function parseDirectiveList() + /** + * @return mixed[] + */ + protected function parseDirectiveList(): array { $directives = []; @@ -346,12 +383,15 @@ protected function parseDirectiveList() return $directives; } - protected function parseDirective() + /** + * @throws SyntaxErrorException + */ + protected function parseDirective(): Directive { $this->expect(Token::TYPE_AT); $nameToken = $this->eatIdentifierToken(); - $args = $this->match(Token::TYPE_LPAREN) ? $this->parseArgumentList() : []; + $args = $this->match(Token::TYPE_LPAREN) ? $this->parseArgumentList() : []; return new Directive($nameToken->getData(), $args, new Location($nameToken->getLine(), $nameToken->getColumn())); } @@ -387,7 +427,10 @@ protected function parseValue() throw $this->createUnexpectedException($this->lookAhead); } - protected function parseList($createType = true) + /** + * @throws SyntaxErrorException + */ + protected function parseList($createType = true): InputList|array { $startToken = $this->eat(Token::TYPE_LSQUARE_BRACE); @@ -403,6 +446,9 @@ protected function parseList($createType = true) return $createType ? new InputList($list, new Location($startToken->getLine(), $startToken->getColumn())) : $list; } + /** + * @throws SyntaxErrorException + */ protected function parseListValue() { switch ($this->lookAhead->getType()) { @@ -418,16 +464,19 @@ protected function parseListValue() return $this->parseVariableReference(); case Token::TYPE_LBRACE: - return $this->parseObject(true); + return $this->parseObject(); case Token::TYPE_LSQUARE_BRACE: return $this->parseList(false); } - throw new SyntaxErrorException('Can\'t parse argument', $this->getLocation()); + throw new SyntaxErrorException("Can't parse argument", $this->getLocation()); } - protected function parseObject($createType = true) + /** + * @throws SyntaxErrorException + */ + protected function parseObject($createType = true): InputObject|array { $startToken = $this->eat(Token::TYPE_LBRACE); @@ -447,7 +496,7 @@ protected function parseObject($createType = true) return $createType ? new InputObject($object, new Location($startToken->getLine(), $startToken->getColumn())) : $object; } - protected function parseFragment() + protected function parseFragment(): Fragment { $this->lex(); $nameToken = $this->eatIdentifierToken(); @@ -481,14 +530,8 @@ protected function eatMulti($types) return null; } - protected function matchMulti($types) + protected function matchMulti($types): bool { - foreach ((array) $types as $type) { - if ($this->peek()->getType() === $type) { - return true; - } - } - - return false; + return in_array($this->peek()->getType(), (array)$types, true); } } diff --git a/src/Parser/Token.php b/src/Parser/Token.php index 92eebdaa..bf5aaa45 100644 --- a/src/Parser/Token.php +++ b/src/Parser/Token.php @@ -10,35 +10,57 @@ class Token { - const TYPE_END = 'end'; - const TYPE_IDENTIFIER = 'identifier'; - const TYPE_NUMBER = 'number'; - const TYPE_STRING = 'string'; - const TYPE_ON = 'on'; - - const TYPE_QUERY = 'query'; - const TYPE_MUTATION = 'mutation'; - const TYPE_FRAGMENT = 'fragment'; - const TYPE_FRAGMENT_REFERENCE = '...'; - const TYPE_TYPED_FRAGMENT = 'typed fragment'; - - const TYPE_LBRACE = '{'; - const TYPE_RBRACE = '}'; - const TYPE_LPAREN = '('; - const TYPE_RPAREN = ')'; - const TYPE_LSQUARE_BRACE = '['; - const TYPE_RSQUARE_BRACE = ']'; - const TYPE_COLON = ':'; - const TYPE_COMMA = ','; - const TYPE_VARIABLE = '$'; - const TYPE_POINT = '.'; - const TYPE_REQUIRED = '!'; - const TYPE_EQUAL = '='; - const TYPE_AT = '@'; - - const TYPE_NULL = 'null'; - const TYPE_TRUE = 'true'; - const TYPE_FALSE = 'false'; + final const TYPE_END = 'end'; + + final const TYPE_IDENTIFIER = 'identifier'; + + final const TYPE_NUMBER = 'number'; + + final const TYPE_STRING = 'string'; + + final const TYPE_ON = 'on'; + + final const TYPE_QUERY = 'query'; + + final const TYPE_MUTATION = 'mutation'; + + final const TYPE_FRAGMENT = 'fragment'; + + final const TYPE_FRAGMENT_REFERENCE = '...'; + + final const TYPE_TYPED_FRAGMENT = 'typed fragment'; + + final const TYPE_LBRACE = '{'; + + final const TYPE_RBRACE = '}'; + + final const TYPE_LPAREN = '('; + + final const TYPE_RPAREN = ')'; + + final const TYPE_LSQUARE_BRACE = '['; + + final const TYPE_RSQUARE_BRACE = ']'; + + final const TYPE_COLON = ':'; + + final const TYPE_COMMA = ','; + + final const TYPE_VARIABLE = '$'; + + final const TYPE_POINT = '.'; + + final const TYPE_REQUIRED = '!'; + + final const TYPE_EQUAL = '='; + + final const TYPE_AT = '@'; + + final const TYPE_NULL = 'null'; + + final const TYPE_TRUE = 'true'; + + final const TYPE_FALSE = 'false'; /** @var mixed */ @@ -58,11 +80,11 @@ public function __construct($type, $line, $column, $data = null) $this->type = $type; $this->data = $data; - $this->line = $line; + $this->line = $line; $this->column = $column; if ($data) { - $tokenLength = mb_strlen($data); + $tokenLength = mb_strlen((string)$data); $tokenLength = $tokenLength > 1 ? $tokenLength - 1 : 0; $this->column = $column - $tokenLength; @@ -81,34 +103,34 @@ public function __construct($type, $line, $column, $data = null) } } - public static function tokenName($tokenType) + public static function tokenName(string $tokenType): string { return [ - self::TYPE_END => 'END', - self::TYPE_IDENTIFIER => 'IDENTIFIER', - self::TYPE_NUMBER => 'NUMBER', - self::TYPE_STRING => 'STRING', - self::TYPE_ON => 'ON', - self::TYPE_QUERY => 'QUERY', - self::TYPE_MUTATION => 'MUTATION', - self::TYPE_FRAGMENT => 'FRAGMENT', + self::TYPE_END => 'END', + self::TYPE_IDENTIFIER => 'IDENTIFIER', + self::TYPE_NUMBER => 'NUMBER', + self::TYPE_STRING => 'STRING', + self::TYPE_ON => 'ON', + self::TYPE_QUERY => 'QUERY', + self::TYPE_MUTATION => 'MUTATION', + self::TYPE_FRAGMENT => 'FRAGMENT', self::TYPE_FRAGMENT_REFERENCE => 'FRAGMENT_REFERENCE', - self::TYPE_TYPED_FRAGMENT => 'TYPED_FRAGMENT', - self::TYPE_LBRACE => 'LBRACE', - self::TYPE_RBRACE => 'RBRACE', - self::TYPE_LPAREN => 'LPAREN', - self::TYPE_RPAREN => 'RPAREN', - self::TYPE_LSQUARE_BRACE => 'LSQUARE_BRACE', - self::TYPE_RSQUARE_BRACE => 'RSQUARE_BRACE', - self::TYPE_COLON => 'COLON', - self::TYPE_COMMA => 'COMMA', - self::TYPE_VARIABLE => 'VARIABLE', - self::TYPE_POINT => 'POINT', - self::TYPE_NULL => 'NULL', - self::TYPE_TRUE => 'TRUE', - self::TYPE_FALSE => 'FALSE', - self::TYPE_REQUIRED => 'REQUIRED', - self::TYPE_AT => 'AT', + self::TYPE_TYPED_FRAGMENT => 'TYPED_FRAGMENT', + self::TYPE_LBRACE => 'LBRACE', + self::TYPE_RBRACE => 'RBRACE', + self::TYPE_LPAREN => 'LPAREN', + self::TYPE_RPAREN => 'RPAREN', + self::TYPE_LSQUARE_BRACE => 'LSQUARE_BRACE', + self::TYPE_RSQUARE_BRACE => 'RSQUARE_BRACE', + self::TYPE_COLON => 'COLON', + self::TYPE_COMMA => 'COMMA', + self::TYPE_VARIABLE => 'VARIABLE', + self::TYPE_POINT => 'POINT', + self::TYPE_NULL => 'NULL', + self::TYPE_TRUE => 'TRUE', + self::TYPE_FALSE => 'FALSE', + self::TYPE_REQUIRED => 'REQUIRED', + self::TYPE_AT => 'AT', ][$tokenType]; } diff --git a/src/Parser/Tokenizer.php b/src/Parser/Tokenizer.php index 7d3c57a7..c63af8e1 100644 --- a/src/Parser/Tokenizer.php +++ b/src/Parser/Tokenizer.php @@ -12,54 +12,59 @@ class Tokenizer { protected $source; - protected $pos = 0; - protected $line = 1; - protected $lineStart = 0; + + protected int $pos = 0; + + protected int $line = 1; + + protected int $lineStart = 0; /** @var Token */ - protected $lookAhead; + protected Token $lookAhead; - protected function initTokenizer($source) + protected function initTokenizer($source): void { - $this->source = $source; + $this->source = $source; $this->lookAhead = $this->next(); } /** * @return Token + * @throws SyntaxErrorException */ - protected function next() + protected function next(): Token { $this->skipWhitespace(); return $this->scan(); } - protected function skipWhitespace() + protected function skipWhitespace(): void { - while ($this->pos < strlen($this->source)) { + while ($this->pos < strlen((string)$this->source)) { $ch = $this->source[$this->pos]; - if ($ch === ' ' || $ch === "\t" || $ch === ',') { - $this->pos++; + if (in_array($ch, [' ', "\t", ','], true)) { + ++$this->pos; } elseif ($ch === '#') { - $this->pos++; + ++$this->pos; while ( - $this->pos < strlen($this->source) && + $this->pos < strlen((string)$this->source) && ($code = ord($this->source[$this->pos])) && $code !== 10 && $code !== 13 && $code !== 0x2028 && $code !== 0x2029 ) { - $this->pos++; + ++$this->pos; } } elseif ($ch === "\r") { - $this->pos++; + ++$this->pos; if ($this->source[$this->pos] === "\n") { - $this->pos++; + ++$this->pos; } - $this->line++; + + ++$this->line; $this->lineStart = $this->pos; } elseif ($ch === "\n") { - $this->pos++; - $this->line++; + ++$this->pos; + ++$this->line; $this->lineStart = $this->pos; } else { break; @@ -72,9 +77,9 @@ protected function skipWhitespace() * * @throws SyntaxErrorException */ - protected function scan() + protected function scan(): Token { - if ($this->pos >= strlen($this->source)) { + if ($this->pos >= strlen((string)$this->source)) { return new Token(Token::TYPE_END, $this->getLine(), $this->getColumn()); } @@ -155,18 +160,18 @@ protected function scan() throw $this->createException('Can\t recognize token type'); } - protected function checkFragment() + protected function checkFragment(): bool { - $this->pos++; + ++$this->pos; $ch = $this->source[$this->pos]; - $this->pos++; + ++$this->pos; $nextCh = $this->source[$this->pos]; $isset = $ch == Token::TYPE_POINT && $nextCh == Token::TYPE_POINT; if ($isset) { - $this->pos++; + ++$this->pos; return true; } @@ -174,55 +179,45 @@ protected function checkFragment() return false; } - protected function scanWord() + protected function scanWord(): Token { $start = $this->pos; - $this->pos++; + ++$this->pos; - while ($this->pos < strlen($this->source)) { + while ($this->pos < strlen((string)$this->source)) { $ch = $this->source[$this->pos]; if ($ch === '_' || $ch === '$' || ('a' <= $ch && $ch <= 'z') || ('A' <= $ch && $ch <= 'Z') || ('0' <= $ch && $ch <= '9')) { - $this->pos++; + ++$this->pos; } else { break; } } - $value = substr($this->source, $start, $this->pos - $start); + $value = substr((string)$this->source, $start, $this->pos - $start); return new Token($this->getKeyword($value), $this->getLine(), $this->getColumn(), $value); } - protected function getKeyword($name) + protected function getKeyword($name): string { - switch ($name) { - case 'null': - return Token::TYPE_NULL; - - case 'true': - return Token::TYPE_TRUE; - - case 'false': - return Token::TYPE_FALSE; - - case 'query': - return Token::TYPE_QUERY; - - case 'fragment': - return Token::TYPE_FRAGMENT; + return match ($name) { + 'null' => Token::TYPE_NULL, + 'true' => Token::TYPE_TRUE, + 'false' => Token::TYPE_FALSE, + 'query' => Token::TYPE_QUERY, + 'fragment' => Token::TYPE_FRAGMENT, + 'mutation' => Token::TYPE_MUTATION, + 'on' => Token::TYPE_ON, + default => Token::TYPE_IDENTIFIER, + }; - case 'mutation': - return Token::TYPE_MUTATION; - - case 'on': - return Token::TYPE_ON; - } - - return Token::TYPE_IDENTIFIER; } - protected function expect($type) + /** + * @throws SyntaxErrorException + */ + protected function expect($type): Token { if ($this->match($type)) { return $this->lex(); @@ -231,12 +226,12 @@ protected function expect($type) throw $this->createUnexpectedException($this->peek()); } - protected function match($type) + protected function match($type): bool { return $this->peek()->getType() === $type; } - protected function scanNumber() + protected function scanNumber(): Token { $start = $this->pos; if ($this->source[$this->pos] === '-') { @@ -246,49 +241,45 @@ protected function scanNumber() $this->skipInteger(); if (isset($this->source[$this->pos]) && $this->source[$this->pos] === '.') { - $this->pos++; + ++$this->pos; $this->skipInteger(); } - $value = substr($this->source, $start, $this->pos - $start); + $value = substr((string)$this->source, $start, $this->pos - $start); - if (strpos($value, '.') === false) { - $value = (int) $value; - } else { - $value = (float) $value; - } + $value = str_contains($value, '.') ? (float)$value : (int)$value; return new Token(Token::TYPE_NUMBER, $this->getLine(), $this->getColumn(), $value); } - protected function skipInteger() + protected function skipInteger(): void { - while ($this->pos < strlen($this->source)) { + while ($this->pos < strlen((string)$this->source)) { $ch = $this->source[$this->pos]; if ('0' <= $ch && $ch <= '9') { - $this->pos++; + ++$this->pos; } else { break; } } } - protected function createException($message) + protected function createException(string $message): SyntaxErrorException { - return new SyntaxErrorException(sprintf('%s', $message), $this->getLocation()); + return new SyntaxErrorException($message, $this->getLocation()); } - protected function getLocation() + protected function getLocation(): Location { return new Location($this->getLine(), $this->getColumn()); } - protected function getColumn() + protected function getColumn(): int|float { return $this->pos - $this->lineStart; } - protected function getLine() + protected function getLine(): int { return $this->line; } @@ -296,25 +287,28 @@ protected function getLine() /* http://facebook.github.io/graphql/October2016/#sec-String-Value */ - protected function scanString() + /** + * @throws SyntaxErrorException + */ + protected function scanString(): Token { - $len = strlen($this->source); - $this->pos++; + $len = strlen((string)$this->source); + ++$this->pos; $value = ''; while ($this->pos < $len) { $ch = $this->source[$this->pos]; if ($ch === '"') { $token = new Token(Token::TYPE_STRING, $this->getLine(), $this->getColumn(), $value); - $this->pos++; + ++$this->pos; return $token; } - - if($ch === '\\' && ($this->pos < ($len - 1))) { - $this->pos++; + + if ($ch === '\\' && ($this->pos < ($len - 1))) { + ++$this->pos; $ch = $this->source[$this->pos]; - switch($ch) { + switch ($ch) { case '"': case '\\': case '/': @@ -332,51 +326,54 @@ protected function scanString() $ch = "\r"; break; case 'u': - $codepoint = substr($this->source, $this->pos + 1, 4); - if( !preg_match('/[0-9A-Fa-f]{4}/', $codepoint)) { + $codepoint = substr((string)$this->source, $this->pos + 1, 4); + if (!preg_match('/[0-9A-Fa-f]{4}/', $codepoint)) { throw $this->createException(sprintf('Invalid string unicode escape sequece "%s"', $codepoint)); } - $ch = html_entity_decode("&#x{$codepoint};", ENT_QUOTES, 'UTF-8'); + + $ch = html_entity_decode(sprintf('&#x%s;', $codepoint), ENT_QUOTES, 'UTF-8'); $this->pos += 4; break; default: throw $this->createException(sprintf('Unexpected string escaped character "%s"', $ch)); - break; } - } - + } + $value .= $ch; - $this->pos++; + ++$this->pos; } throw $this->createUnexpectedTokenTypeException(Token::TYPE_END); } - protected function end() + protected function end(): bool { return $this->lookAhead->getType() === Token::TYPE_END; } - protected function peek() + protected function peek(): Token { return $this->lookAhead; } - protected function lex() + /** + * @throws SyntaxErrorException + */ + protected function lex(): Token { - $prev = $this->lookAhead; + $prev = $this->lookAhead; $this->lookAhead = $this->next(); return $prev; } - protected function createUnexpectedException(Token $token) + protected function createUnexpectedException(Token $token): SyntaxErrorException { return $this->createUnexpectedTokenTypeException($token->getType()); } - protected function createUnexpectedTokenTypeException($tokenType) + protected function createUnexpectedTokenTypeException(string $tokenType): SyntaxErrorException { return $this->createException(sprintf('Unexpected token "%s"', Token::tokenName($tokenType))); } diff --git a/src/Relay/Connection/ArrayConnection.php b/src/Relay/Connection/ArrayConnection.php index e1b1750c..bd66c554 100644 --- a/src/Relay/Connection/ArrayConnection.php +++ b/src/Relay/Connection/ArrayConnection.php @@ -7,18 +7,18 @@ namespace Youshido\GraphQL\Relay\Connection; - class ArrayConnection { + final const PREFIX = 'arrayconnection:'; - const PREFIX = 'arrayconnection:'; - - public static function cursorForObjectInConnection($data, $object) + public static function cursorForObjectInConnection($data, $object): ?string { - if (!is_array($data)) return null; + if (!is_array($data)) { + return null; + } - $index = array_search($object, $data); - return $index === false ? null : (string) self::keyToCursor($index); + $index = array_search($object, $data, true); + return $index === false ? null : self::keyToCursor($index); } /** @@ -27,87 +27,86 @@ public static function cursorForObjectInConnection($data, $object) * @deprecated * Use keyToCursor instead. */ - public static function offsetToCursor($offset) + public static function offsetToCursor(int $offset): string { - return self::keyToCursor($offset); + return self::keyToCursor($offset); } - public static function keyToCursor($key) + public static function keyToCursor(string $key): string { - return base64_encode(self::PREFIX . $key); + return base64_encode(self::PREFIX . $key); } /** * @param $cursor string * - * @return int|null + * @return int|string|null * @deprecated Use cursorToKey instead. */ - public static function cursorToOffset($cursor) + public static function cursorToOffset(string $cursor): int|string|null { return self::cursorToKey($cursor); } - /** - * Converts a cursor to its array key. - * - * @param $cursor - * @return null|string - */ - public static function cursorToKey($cursor) { - if ($decoded = base64_decode($cursor)) { - return substr($decoded, strlen(self::PREFIX)); - } - return null; + /** + * Converts a cursor to its array key. + */ + public static function cursorToKey(?string $cursor): ?string + { + if ($cursor === null) { + return null; + } + + $decoded = base64_decode($cursor); + + if ($decoded !== '' && $decoded !== '0') { + return substr($decoded, strlen(self::PREFIX)); + } + + return null; } - /** - * Converts a cursor to an array offset. - * - * @param $cursor - * The cursor string. - * @param $default - * The default value, in case the cursor is not given. - * @param array $array - * The array to use in counting the offset. If empty, assumed to be an indexed array. - * @return int|null - */ - public static function cursorToOffsetWithDefault($cursor, $default, $array = []) + /** + * Converts a cursor to an array offset. + * + * @param $cursor + * The cursor string. + * @param $default + * The default value, in case the cursor is not given. + * @param array $array + * The array to use in counting the offset. If empty, assumed to be an indexed array. + */ + public static function cursorToOffsetWithDefault(mixed $cursor, mixed $default, array $array = []): ?int { if (!is_string($cursor)) { return $default; } $key = self::cursorToKey($cursor); - if (empty($array)) { - $offset = $key; - } - else { - $offset = array_search($key, array_keys($array)); - } + $offset = $array === [] ? $key : array_search($key, array_keys($array), true); - return is_null($offset) ? $default : (int) $offset; + return is_null($offset) ? $default : (int)$offset; } - public static function connectionFromArray(array $data, array $args = []) + public static function connectionFromArray(array $data, array $args = []): array { return self::connectionFromArraySlice($data, $args, 0, count($data)); } - public static function connectionFromArraySlice(array $data, array $args, $sliceStart, $arrayLength) + public static function connectionFromArraySlice(array $data, array $args, $sliceStart, $arrayLength): array { - $after = isset($args['after']) ? $args['after'] : null; - $before = isset($args['before']) ? $args['before'] : null; - $first = isset($args['first']) ? $args['first'] : null; - $last = isset($args['last']) ? $args['last'] : null; + $after = $args['after'] ?? null; + $before = $args['before'] ?? null; + $first = $args['first'] ?? null; + $last = $args['last'] ?? null; $sliceEnd = $sliceStart + count($data); $beforeOffset = ArrayConnection::cursorToOffsetWithDefault($before, $arrayLength, $data); - $afterOffset = ArrayConnection::cursorToOffsetWithDefault($after, -1, $data); + $afterOffset = ArrayConnection::cursorToOffsetWithDefault($after, -1, $data); $startOffset = max($sliceStart - 1, $afterOffset, -1) + 1; - $endOffset = min($sliceEnd, $beforeOffset, $arrayLength); + $endOffset = min($sliceEnd, $beforeOffset, $arrayLength); if ($first) { $endOffset = min($endOffset, $startOffset + $first); @@ -117,34 +116,34 @@ public static function connectionFromArraySlice(array $data, array $args, $slice $startOffset = max($startOffset, $endOffset - $last); } - $arraySliceStart = max($startOffset - $sliceStart, 0); - $arraySliceEnd = count($data) - ($sliceEnd - $endOffset) - $arraySliceStart; + $arraySliceStart = max($startOffset - $sliceStart, 0); + $arraySliceEnd = count($data) - ($sliceEnd - $endOffset) - $arraySliceStart; $slice = array_slice($data, $arraySliceStart, $arraySliceEnd, true); $edges = array_map(['self', 'edgeForObjectWithIndex'], $slice, array_keys($slice)); - $firstEdge = array_key_exists(0, $edges) ? $edges[0] : null; - $lastEdge = count($edges) > 0 ? $edges[count($edges) - 1] : null; + $firstEdge = $edges[0] ?? null; + $lastEdge = $edges !== [] ? $edges[count($edges) - 1] : null; $lowerBound = $after ? $afterOffset + 1 : 0; $upperBound = $before ? $beforeOffset : $arrayLength; return [ 'totalCount' => $arrayLength, - 'edges' => $edges, - 'pageInfo' => [ - 'startCursor' => $firstEdge ? $firstEdge['cursor'] : null, - 'endCursor' => $lastEdge ? $lastEdge['cursor'] : null, - 'hasPreviousPage' => $last ? $startOffset > $lowerBound : false, - 'hasNextPage' => $first ? $endOffset < $upperBound : false, + 'edges' => $edges, + 'pageInfo' => [ + 'startCursor' => $firstEdge ? $firstEdge['cursor'] : null, + 'endCursor' => $lastEdge ? $lastEdge['cursor'] : null, + 'hasPreviousPage' => $last && $startOffset > $lowerBound, + 'hasNextPage' => $first && $endOffset < $upperBound, ], ]; } - public static function edgeForObjectWithIndex($object, $index) + public static function edgeForObjectWithIndex($object, string $index): array { return [ 'cursor' => ArrayConnection::keyToCursor($index), - 'node' => $object + 'node' => $object ]; } diff --git a/src/Relay/Connection/Connection.php b/src/Relay/Connection/Connection.php index 67ec001a..9b2b8e8d 100644 --- a/src/Relay/Connection/Connection.php +++ b/src/Relay/Connection/Connection.php @@ -8,6 +8,7 @@ namespace Youshido\GraphQL\Relay\Connection; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Relay\Type\PageInfoType; use Youshido\GraphQL\Type\AbstractType; use Youshido\GraphQL\Type\ListType\ListType; @@ -19,12 +20,12 @@ class Connection { - public static function connectionArgs() + public static function connectionArgs(): array { return array_merge(self::forwardArgs(), self::backwardArgs()); } - public static function forwardArgs() + public static function forwardArgs(): array { return [ 'after' => ['type' => TypeMap::TYPE_STRING], @@ -32,101 +33,96 @@ public static function forwardArgs() ]; } - public static function backwardArgs() + public static function backwardArgs(): array { return [ 'before' => ['type' => TypeMap::TYPE_STRING], - 'last' => ['type' => TypeMap::TYPE_INT] + 'last' => ['type' => TypeMap::TYPE_INT] ]; } /** - * @param AbstractType $type - * @param null|string $name - * @param array $config + * @param null|string $name * @option string edgeFields * - * @return ObjectType + * @throws ConfigurationException */ - public static function edgeDefinition(AbstractType $type, $name = null, $config = []) + public static function edgeDefinition(AbstractType $type, $name = null, array $config = []): ObjectType { - $name = $name ?: $type->getName(); - $edgeFields = !empty($config['edgeFields']) ? $config['edgeFields'] : []; + $name = $name ?: $type->getName(); + $edgeFields = empty($config['edgeFields']) ? [] : $config['edgeFields']; - $edgeType = new ObjectType([ - 'name' => $name . 'Edge', + return new ObjectType([ + 'name' => $name . 'Edge', 'description' => 'An edge in a connection.', - 'fields' => array_merge([ - 'node' => [ - 'type' => $type, + 'fields' => array_merge([ + 'node' => [ + 'type' => $type, 'description' => 'The item at the end of the edge', - 'resolve' => [__CLASS__, 'getNode'], + 'resolve' => [__CLASS__, 'getNode'], ], 'cursor' => [ - 'type' => TypeMap::TYPE_STRING, + 'type' => TypeMap::TYPE_STRING, 'description' => 'A cursor for use in pagination' ] ], $edgeFields) ]); - - return $edgeType; } /** - * @param AbstractType $type - * @param null|string $name - * @param array $config + * @param null|string $name * @option string connectionFields * - * @return ObjectType + * @throws ConfigurationException + * @throws ConfigurationException + * @throws ConfigurationException + * @throws ConfigurationException */ - public static function connectionDefinition(AbstractType $type, $name = null, $config = []) + public static function connectionDefinition(AbstractType $type, $name = null, array $config = []): ObjectType { - $name = $name ?: $type->getName(); - $connectionFields = !empty($config['connectionFields']) ? $config['connectionFields'] : []; + $name = $name ?: $type->getName(); + $connectionFields = empty($config['connectionFields']) ? [] : $config['connectionFields']; - $connectionType = new ObjectType([ - 'name' => $name . 'Connection', + return new ObjectType([ + 'name' => $name . 'Connection', 'description' => 'A connection to a list of items.', - 'fields' => array_merge([ + 'fields' => array_merge([ 'totalCount' => [ - 'type' => new NonNullType(new IntType()), + 'type' => new NonNullType(new IntType()), 'description' => 'How many nodes.', - 'resolve' => [__CLASS__, 'getTotalCount'], + 'resolve' => [__CLASS__, 'getTotalCount'], ], 'pageInfo' => [ - 'type' => new NonNullType(new PageInfoType()), + 'type' => new NonNullType(new PageInfoType()), 'description' => 'Information to aid in pagination.', - 'resolve' => [__CLASS__, 'getPageInfo'], + 'resolve' => [__CLASS__, 'getPageInfo'], ], - 'edges' => [ - 'type' => new ListType(self::edgeDefinition($type, $name, $config)), + 'edges' => [ + 'type' => new ListType(self::edgeDefinition($type, $name, $config)), 'description' => 'A list of edges.', - 'resolve' => [__CLASS__, 'getEdges'], + 'resolve' => [__CLASS__, 'getEdges'], ] ], $connectionFields) ]); - - return $connectionType; } - public static function getTotalCount($value) + public static function getTotalCount(array $value) { - return isset($value['totalCount']) ? $value['totalCount'] : -1; + return $value['totalCount'] ?? -1; } - public static function getEdges($value) + public static function getEdges(array $value) { - return isset($value['edges']) ? $value['edges'] : null; + return $value['edges'] ?? null; } - public static function getPageInfo($value) + public static function getPageInfo(array $value) { - return isset($value['pageInfo']) ? $value['pageInfo'] : null; + return $value['pageInfo'] ?? null; } - public static function getNode($value) + public static function getNode(array $value) { - return isset($value['node']) ? $value['node'] : null; + return $value['node'] ?? null; } } diff --git a/src/Relay/Field/GlobalIdField.php b/src/Relay/Field/GlobalIdField.php index d9569e83..c4aec0e5 100644 --- a/src/Relay/Field/GlobalIdField.php +++ b/src/Relay/Field/GlobalIdField.php @@ -9,6 +9,7 @@ namespace Youshido\GraphQL\Relay\Field; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Execution\ResolveInfo; use Youshido\GraphQL\Field\AbstractField; use Youshido\GraphQL\Relay\Node; @@ -23,31 +24,37 @@ class GlobalIdField extends AbstractField /** * @param string $typeName + * @throws ConfigurationException */ public function __construct($typeName) { $this->typeName = $typeName; $config = [ - 'type' => $this->getType(), - 'name' => $this->getName(), - 'resolve' => [$this, 'resolve'] + 'type' => $this->getType(), + 'name' => $this->getName(), + 'resolve' => function ($value, array $args, ResolveInfo $info): ?string { + return $this->resolve($value, $args, $info); + } ]; parent::__construct($config); } - public function getName() + public function getName(): string { return 'id'; } - public function getDescription() + public function getDescription(): string { return 'The ID of an object'; } - public function getType() + /** + * @throws ConfigurationException + */ + public function getType(): NonNullType { return new NonNullType(new IdType()); } @@ -55,7 +62,7 @@ public function getType() /** * @inheritdoc */ - public function resolve($value, array $args, ResolveInfo $info) + public function resolve($value, array $args, ResolveInfo $info): ?string { return $value ? Node::toGlobalId($this->typeName, $value['id']) : null; } diff --git a/src/Relay/Field/NodeField.php b/src/Relay/Field/NodeField.php index 449465f8..87898d47 100644 --- a/src/Relay/Field/NodeField.php +++ b/src/Relay/Field/NodeField.php @@ -10,6 +10,7 @@ use Youshido\GraphQL\Config\Field\FieldConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Execution\ResolveInfo; use Youshido\GraphQL\Field\AbstractField; use Youshido\GraphQL\Field\InputField; @@ -21,51 +22,49 @@ class NodeField extends AbstractField { + protected FetcherInterface $fetcher; - /** @var FetcherInterface */ - protected $fetcher; - - /** @var NodeInterfaceType */ - protected $type; + protected NodeInterfaceType $type; public function __construct(FetcherInterface $fetcher) { $this->fetcher = $fetcher; - $this->type = (new NodeInterfaceType())->setFetcher($this->fetcher); + $this->type = (new NodeInterfaceType())->setFetcher($this->fetcher); - parent::__construct([]); + parent::__construct(); } - public function getName() + public function getName(): string { return 'node'; } - public function getDescription() + public function getDescription(): string { return 'Fetches an object given its ID'; } - public function build(FieldConfig $config) + /** + * @throws ConfigurationException + */ + public function build(FieldConfig $config): void { $config->addArgument(new InputField([ - 'name' => 'id', - 'type' => new NonNullType(new IdType()), + 'name' => 'id', + 'type' => new NonNullType(new IdType()), 'description' => 'The ID of an object' ])); } - public function getType() + public function getType(): mixed { return $this->type; } - public function resolve($value, array $args, ResolveInfo $info) + public function resolve($value, array $args, ResolveInfo $info): mixed { list($type, $id) = Node::fromGlobalId($args['id']); return $this->fetcher->resolveNode($type, $id); } - - } diff --git a/src/Relay/Node.php b/src/Relay/Node.php index 3e360333..cef53b49 100644 --- a/src/Relay/Node.php +++ b/src/Relay/Node.php @@ -8,6 +8,8 @@ namespace Youshido\GraphQL\Relay; +use InvalidArgumentException; + class Node { @@ -16,16 +18,18 @@ class Node * * @return array with type and id element */ - public static function fromGlobalId($id) + public static function fromGlobalId($id): array { - $decoded = base64_decode($id, true); + $decoded = base64_decode((string)$id, true); if (!$decoded) { - throw new \InvalidArgumentException('ID must be a valid base 64 string'); + throw new InvalidArgumentException('ID must be a valid base 64 string'); } + $decodedParts = explode(':', $decoded, 2); if (count($decodedParts) !== 2) { - throw new \InvalidArgumentException('ID was not correctly formed'); + throw new InvalidArgumentException('ID was not correctly formed'); } + return $decodedParts; } @@ -35,7 +39,7 @@ public static function fromGlobalId($id) * * @return string global id */ - public static function toGlobalId($typeName, $id) + public static function toGlobalId($typeName, $id): string { return base64_encode(implode(':', [$typeName, $id])); } diff --git a/src/Relay/NodeInterfaceType.php b/src/Relay/NodeInterfaceType.php index 045726ee..5f50e9d5 100644 --- a/src/Relay/NodeInterfaceType.php +++ b/src/Relay/NodeInterfaceType.php @@ -9,6 +9,8 @@ namespace Youshido\GraphQL\Relay; +use Youshido\GraphQL\Config\Object\InterfaceTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Relay\Fetcher\FetcherInterface; use Youshido\GraphQL\Relay\Field\GlobalIdField; use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType; @@ -19,23 +21,23 @@ class NodeInterfaceType extends AbstractInterfaceType /** @var FetcherInterface */ //todo: maybe there are better solution protected $fetcher; - public function getName() + public function getName(): string { return 'NodeInterface'; } - public function build($config) + /** + * @throws ConfigurationException + */ + public function build(InterfaceTypeConfig $config): void { $config->addField(new GlobalIdField('NodeInterface')); } public function resolveType($object) { - if ($this->fetcher) { - return $this->fetcher->resolveType($object); - } + return $this->fetcher?->resolveType($object); - return null; } /** @@ -48,10 +50,8 @@ public function getFetcher() /** * @param FetcherInterface $fetcher - * - * @return NodeInterfaceType */ - public function setFetcher($fetcher) + public function setFetcher($fetcher): static { $this->fetcher = $fetcher; diff --git a/src/Relay/RelayMutation.php b/src/Relay/RelayMutation.php index 501d4151..ac51ae09 100644 --- a/src/Relay/RelayMutation.php +++ b/src/Relay/RelayMutation.php @@ -8,6 +8,7 @@ namespace Youshido\GraphQL\Relay; +use Exception; use Youshido\GraphQL\Execution\ResolveInfo; use Youshido\GraphQL\Field\Field; use Youshido\GraphQL\Field\InputField; @@ -21,28 +22,25 @@ class RelayMutation { /** - * @param string $name - * @param array $args + * @param string $name * @param AbstractObjectType|array $output - * @param callable $resolveFunction * - * @return Field * - * @throws \Exception + * @throws Exception */ - public static function buildMutation($name, array $args, $output, callable $resolveFunction) + public static function buildMutation($name, array $args, $output, callable $resolveFunction): Field { if (!is_array($output) || (is_object($output) && !($output instanceof AbstractObjectType))) { - throw new \Exception('Output can be instance of AbstractObjectType or array of fields'); + throw new Exception('Output can be instance of AbstractObjectType or array of fields'); } return new Field([ - 'name' => $name, - 'args' => [ + 'name' => $name, + 'args' => [ new InputField([ 'name' => 'input', 'type' => new NonNullType(new InputObjectType([ - 'name' => ucfirst($name) . 'Input', + 'name' => ucfirst($name) . 'Input', 'fields' => array_merge( $args, [new InputField(['name' => 'clientMutationId', 'type' => new NonNullType(new StringType())])] @@ -50,22 +48,21 @@ public static function buildMutation($name, array $args, $output, callable $reso ])) ]) ], - 'type' => new ObjectType([ + 'type' => new ObjectType([ 'fields' => is_object($output) ? $output : array_merge( $output, [new Field(['name' => 'clientMutationId', 'type' => new NonNullType(new StringType())])] ), - 'name' => ucfirst($name) . 'Payload' + 'name' => ucfirst($name) . 'Payload' ]), - 'resolve' => function ($value, $args, ResolveInfo $info) use ($resolveFunction) { + 'resolve' => static function ($value, array $args, ResolveInfo $info) use ($resolveFunction) { $resolveValue = $resolveFunction($value, $args['input'], $args, $info); - if (is_object($resolveValue)) { $resolveValue->clientMutationId = $args['input']['clientMutationId']; } elseif (is_array($resolveValue)) { $resolveValue['clientMutationId'] = $args['input']['clientMutationId']; } - + return $resolveValue; } ]); diff --git a/src/Relay/Type/PageInfoType.php b/src/Relay/Type/PageInfoType.php index 74d786fd..c3606cc2 100644 --- a/src/Relay/Type/PageInfoType.php +++ b/src/Relay/Type/PageInfoType.php @@ -9,6 +9,8 @@ namespace Youshido\GraphQL\Relay\Type; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Scalar\BooleanType; @@ -16,29 +18,32 @@ class PageInfoType extends AbstractObjectType { - public function build($config) + /** + * @throws ConfigurationException + */ + public function build(ObjectTypeConfig $config): void { $config->addFields([ - 'hasNextPage' => [ - 'type' => new NonNullType(new BooleanType()), + 'hasNextPage' => [ + 'type' => new NonNullType(new BooleanType()), 'description' => 'When paginating forwards, are there more items?' ], 'hasPreviousPage' => [ - 'type' => new NonNullType(new BooleanType()), + 'type' => new NonNullType(new BooleanType()), 'description' => 'When paginating backwards, are there more items?' ], - 'startCursor' => [ - 'type' => new StringType(), + 'startCursor' => [ + 'type' => new StringType(), 'description' => 'When paginating backwards, the cursor to continue.' ], - 'endCursor' => [ - 'type' => new StringType(), + 'endCursor' => [ + 'type' => new StringType(), 'description' => 'When paginating forwards, the cursor to continue.' ], ]); } - public function getDescription() + public function getDescription(): string { return "Information about pagination in a connection."; } diff --git a/src/Schema/AbstractSchema.php b/src/Schema/AbstractSchema.php index 349cdd84..5d64145c 100644 --- a/src/Schema/AbstractSchema.php +++ b/src/Schema/AbstractSchema.php @@ -10,25 +10,30 @@ use Youshido\GraphQL\Config\Schema\SchemaConfig; -use Youshido\GraphQL\Type\SchemaTypesList; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\SchemaDirectivesList; +use Youshido\GraphQL\Type\SchemaTypesList; abstract class AbstractSchema { - /** @var SchemaConfig */ - protected $config; + protected SchemaConfig $config; - public function __construct($config = []) + /** + * @throws ConfigurationException + */ + public function __construct(array $config = []) { if (!array_key_exists('query', $config)) { $config['query'] = new InternalSchemaQueryObject(['name' => $this->getName($config) . 'Query']); } + if (!array_key_exists('mutation', $config)) { $config['mutation'] = new InternalSchemaMutationObject(['name' => $this->getName($config) . 'Mutation']); } + if (!array_key_exists('types', $config)) { - $config['types'] = []; + $config['types'] = []; } $this->config = new SchemaConfig($config, $this); @@ -38,12 +43,18 @@ public function __construct($config = []) abstract public function build(SchemaConfig $config); - public function addQueryField($field, $fieldInfo = null) + /** + * @throws ConfigurationException + */ + public function addQueryField($field, $fieldInfo = null): void { $this->getQueryType()->addField($field, $fieldInfo); } - public function addMutationField($field, $fieldInfo = null) + /** + * @throws ConfigurationException + */ + public function addMutationField($field, $fieldInfo = null): void { $this->getMutationType()->addField($field, $fieldInfo); } @@ -74,10 +85,10 @@ public function getDirectiveList() return $this->config->getDirectiveList(); } - public function getName($config) + public function getName(array $config) { $defaultName = 'RootSchema'; - return isset($config["name"])? $config["name"] : $defaultName; + return $config["name"] ?? $defaultName; } } diff --git a/src/Schema/InternalSchemaMutationObject.php b/src/Schema/InternalSchemaMutationObject.php index a31e112b..89596402 100644 --- a/src/Schema/InternalSchemaMutationObject.php +++ b/src/Schema/InternalSchemaMutationObject.php @@ -9,11 +9,12 @@ namespace Youshido\GraphQL\Schema; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\Object\AbstractObjectType; class InternalSchemaMutationObject extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { } diff --git a/src/Schema/InternalSchemaQueryObject.php b/src/Schema/InternalSchemaQueryObject.php index bf98d9e7..bc9cef26 100644 --- a/src/Schema/InternalSchemaQueryObject.php +++ b/src/Schema/InternalSchemaQueryObject.php @@ -9,11 +9,12 @@ namespace Youshido\GraphQL\Schema; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\Object\AbstractObjectType; class InternalSchemaQueryObject extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { } diff --git a/src/Schema/Schema.php b/src/Schema/Schema.php index b6cfb45a..edc212ac 100644 --- a/src/Schema/Schema.php +++ b/src/Schema/Schema.php @@ -12,7 +12,7 @@ final class Schema extends AbstractSchema { - public function build(SchemaConfig $config) + public function build(SchemaConfig $config): void { } } diff --git a/src/Type/AbstractInterfaceTypeInterface.php b/src/Type/AbstractInterfaceTypeInterface.php index 2d76ef59..d84e4be0 100644 --- a/src/Type/AbstractInterfaceTypeInterface.php +++ b/src/Type/AbstractInterfaceTypeInterface.php @@ -13,8 +13,6 @@ interface AbstractInterfaceTypeInterface { /** * @param $object object from resolve function - * - * @return AbstractType */ - public function resolveType($object); + public function resolveType(object $object): ?AbstractType; } diff --git a/src/Type/AbstractType.php b/src/Type/AbstractType.php index 646edbb8..e583f5c4 100644 --- a/src/Type/AbstractType.php +++ b/src/Type/AbstractType.php @@ -8,54 +8,42 @@ namespace Youshido\GraphQL\Type; - -use Youshido\GraphQL\Type\Object\AbstractObjectType; - abstract class AbstractType implements TypeInterface { - protected $lastValidationError = null; + protected $lastValidationError; - public function isCompositeType() + public function isCompositeType(): bool { return false; } - /** - * @return AbstractType - */ - public function getType() + public function getType(): mixed { return $this; } - /** - * @return AbstractType - */ - public function getNamedType() + public function getNamedType(): mixed { return $this->getType(); } - /** - * @return AbstractType|AbstractObjectType - */ - public function getNullableType() + public function getNullableType(): mixed { return $this; } - public function getValidationError($value = null) + public function getValidationError($value = null): ?string { return $this->lastValidationError; } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { return true; } - public function parseValue($value) + public function parseValue($value): mixed { return $value; } @@ -65,18 +53,18 @@ public function parseInputValue($value) return $this->parseValue($value); } - public function serialize($value) + public function serialize($value): mixed { return $value; } - public function isInputType() + public function isInputType(): bool { return false; } - public function __toString() + public function __toString(): string { - return $this->getName(); + return $this->getName() ?? ''; } } diff --git a/src/Type/CompositeTypeInterface.php b/src/Type/CompositeTypeInterface.php index 3e631676..8e074be2 100644 --- a/src/Type/CompositeTypeInterface.php +++ b/src/Type/CompositeTypeInterface.php @@ -7,11 +7,8 @@ * @author Alexandr Viniychuk * created: 3:48 PM 4/29/16 */ + interface CompositeTypeInterface { - - /** - * @return AbstractType - */ - public function getTypeOf(); + public function getTypeOf(): mixed; } diff --git a/src/Type/Enum/AbstractEnumType.php b/src/Type/Enum/AbstractEnumType.php index 97b764c7..4679125d 100644 --- a/src/Type/Enum/AbstractEnumType.php +++ b/src/Type/Enum/AbstractEnumType.php @@ -10,6 +10,7 @@ use Youshido\GraphQL\Config\Object\EnumTypeConfig; use Youshido\GraphQL\Config\Traits\ConfigAwareTrait; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\AbstractType; use Youshido\GraphQL\Type\Traits\AutoNameTrait; use Youshido\GraphQL\Type\TypeMap; @@ -17,16 +18,17 @@ abstract class AbstractEnumType extends AbstractType { - use AutoNameTrait, ConfigAwareTrait; + use AutoNameTrait; + use ConfigAwareTrait; /** * ObjectType constructor. - * @param $config + * @throws ConfigurationException */ - public function __construct($config = []) + public function __construct(array $config = []) { - if (empty($config)) { - $config['name'] = $this->getName(); + if ($config === []) { + $config['name'] = $this->getName(); $config['values'] = $this->getValues(); } @@ -36,19 +38,20 @@ public function __construct($config = []) /** * @return String predefined type kind */ - public function getKind() + public function getKind(): string { return TypeMap::KIND_ENUM; } /** * @param $value mixed - * - * @return bool */ - public function isValidValue($value) + public function isValidValue(mixed $value): bool { - if (is_null($value)) return true; + if (is_null($value)) { + return true; + } + foreach ($this->getConfig()->get('values') as $item) { if ($value === $item['name'] || $value === $item['value']) { return true; @@ -58,20 +61,17 @@ public function isValidValue($value) return false; } - public function getValidationError($value = null) + public function getValidationError($value = null): ?string { - $allowedValues = array_map(function (array $value) { + $allowedValues = array_map(static function (array $value): string { return sprintf('%s (%s)', $value['name'], $value['value']); }, $this->getConfig()->get('values')); return sprintf('Value must be one of the allowed ones: %s', implode(', ', $allowedValues)); } - /** - * @return array - */ - abstract public function getValues(); + abstract public function getValues(): array; - public function serialize($value) + public function serialize($value): mixed { foreach ($this->getConfig()->get('values') as $valueItem) { if ($value === $valueItem['value']) { @@ -82,7 +82,7 @@ public function serialize($value) return null; } - public function parseValue($value) + public function parseValue($value): mixed { foreach ($this->getConfig()->get('values') as $valueItem) { if ($value === $valueItem['name']) { diff --git a/src/Type/Enum/EnumType.php b/src/Type/Enum/EnumType.php index 63ce6f9c..a16475c7 100644 --- a/src/Type/Enum/EnumType.php +++ b/src/Type/Enum/EnumType.php @@ -14,10 +14,11 @@ final class EnumType extends AbstractEnumType public function __construct(array $config) { + parent::__construct($config); $this->config = new EnumTypeConfig($config, $this, true); } - public function getValues() + public function getValues(): array { return $this->getConfig()->getValues(); } diff --git a/src/Type/InputObject/AbstractInputObjectType.php b/src/Type/InputObject/AbstractInputObjectType.php index 15312d28..1ea74fdb 100644 --- a/src/Type/InputObject/AbstractInputObjectType.php +++ b/src/Type/InputObject/AbstractInputObjectType.php @@ -9,7 +9,10 @@ namespace Youshido\GraphQL\Type\InputObject; +use Exception; +use Youshido\GraphQL\Config\AbstractConfig; use Youshido\GraphQL\Config\Object\InputObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Field\InputFieldInterface; use Youshido\GraphQL\Parser\Ast\ArgumentValue\InputObject; use Youshido\GraphQL\Parser\Ast\ArgumentValue\Variable; @@ -21,11 +24,12 @@ abstract class AbstractInputObjectType extends AbstractType { - use AutoNameTrait, FieldsAwareObjectTrait; + use AutoNameTrait; + use FieldsAwareObjectTrait; protected $isBuilt = false; - public function getConfig() + public function getConfig(): InputObjectTypeConfig { if (!$this->isBuilt) { $this->isBuilt = true; @@ -35,6 +39,9 @@ public function getConfig() return $this->config; } + /** + * @throws ConfigurationException + */ public function __construct($config = []) { if (empty($config)) { @@ -42,6 +49,7 @@ public function __construct($config = []) 'name' => $this->getName() ]; } + $this->config = new InputObjectTypeConfig($config, $this); } @@ -50,7 +58,7 @@ public function __construct($config = []) */ abstract public function build($config); - public function isValidValue($value) + public function isValidValue(mixed $value): bool { if ($value instanceof InputObject) { $value = $value->getValue(); @@ -64,8 +72,8 @@ public function isValidValue($value) return false; } - $typeConfig = $this->getConfig(); - $requiredFields = array_filter($typeConfig->getFields(), function (InputFieldInterface $field) { + $typeConfig = $this->getConfig(); + $requiredFields = array_filter($typeConfig->getFields(), static function (InputFieldInterface $field): bool { return $field->getType()->getKind() == TypeMap::KIND_NON_NULL; }); @@ -77,7 +85,7 @@ public function isValidValue($value) $field = $typeConfig->getField($valueKey); if (!$field->getType()->isValidValue($valueItem)) { - $error = $field->getType()->getValidationError($valueItem) ?: '(no details available)'; + $error = $field->getType()->getValidationError($valueItem) ?: '(no details available)'; $this->lastValidationError = sprintf('Not valid type for field "%s" in input type "%s": %s', $field->getName(), $this->getName(), $error); return false; } @@ -86,27 +94,34 @@ public function isValidValue($value) unset($requiredFields[$valueKey]); } } - if (count($requiredFields)) { + + if ($requiredFields !== []) { $this->lastValidationError = sprintf('%s %s required on %s', implode(', ', array_keys($requiredFields)), count($requiredFields) > 1 ? 'are' : 'is', $typeConfig->getName()); } - return !(count($requiredFields) > 0); + return count($requiredFields) <= 0; } - public function getKind() + public function getKind(): string { return TypeMap::KIND_INPUT_OBJECT; } - public function isInputType() + public function isInputType(): bool { return true; } - public function parseValue($value) + /** + * @throws Exception + */ + public function parseValue($value): mixed { - if (is_null($value)) return null; - if($value instanceof InputObject) { + if (is_null($value)) { + return null; + } + + if ($value instanceof InputObject) { $value = $value->getValue(); } @@ -117,8 +132,9 @@ public function parseValue($value) } if (!($inputField = $typeConfig->getField($valueKey))) { - throw new \Exception(sprintf('Invalid field "%s" on %s', $valueKey, $typeConfig->getName())); + throw new Exception(sprintf('Invalid field "%s" on %s', $valueKey, $typeConfig->getName())); } + $value[$valueKey] = $inputField->getType()->parseValue($item); } diff --git a/src/Type/InputObject/InputObjectType.php b/src/Type/InputObject/InputObjectType.php index a44fc03b..8ee2f963 100644 --- a/src/Type/InputObject/InputObjectType.php +++ b/src/Type/InputObject/InputObjectType.php @@ -9,21 +9,26 @@ namespace Youshido\GraphQL\Type\InputObject; use Youshido\GraphQL\Config\Object\InputObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; final class InputObjectType extends AbstractInputObjectType { + /** + * @throws ConfigurationException + */ public function __construct($config) { + parent::__construct($config); $this->config = new InputObjectTypeConfig($config, $this, true); } /** * @inheritdoc - * + * * @codeCoverageIgnore */ - public function build($config) + public function build($config): void { } } diff --git a/src/Type/InputTypeInterface.php b/src/Type/InputTypeInterface.php index 1fd7eab1..278c3f39 100644 --- a/src/Type/InputTypeInterface.php +++ b/src/Type/InputTypeInterface.php @@ -9,50 +9,41 @@ namespace Youshido\GraphQL\Type; -use Youshido\GraphQL\Config\AbstractConfig; - interface InputTypeInterface { /** - * @return String type name + * @return string|null type name */ - public function getName(); + public function getName(): ?string; /** * @return String predefined type kind */ - public function getKind(); + public function getKind(): string; /** * @return String type description */ - public function getDescription(); + public function getDescription(): string; /** * Coercing value received as input to current type * * @param $value - * @return mixed */ - public function parseValue($value); + public function parseValue($value): mixed; /** * Coercing result to current type * * @param $value - * @return mixed */ - public function serialize($value); + public function serialize($value): mixed; /** * @param $value mixed - * - * @return bool */ - public function isValidValue($value); + public function isValidValue(mixed $value): bool; - /** - * @return AbstractConfig - */ public function getConfig(); } \ No newline at end of file diff --git a/src/Type/InterfaceType/AbstractInterfaceType.php b/src/Type/InterfaceType/AbstractInterfaceType.php index 6e26a354..e4882ef7 100644 --- a/src/Type/InterfaceType/AbstractInterfaceType.php +++ b/src/Type/InterfaceType/AbstractInterfaceType.php @@ -10,6 +10,7 @@ use Youshido\GraphQL\Config\Object\InterfaceTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\AbstractType; use Youshido\GraphQL\Type\Traits\AutoNameTrait; use Youshido\GraphQL\Type\Traits\FieldsAwareObjectTrait; @@ -18,11 +19,12 @@ abstract class AbstractInterfaceType extends AbstractType { - use FieldsAwareObjectTrait, AutoNameTrait; + use FieldsAwareObjectTrait; + use AutoNameTrait; - protected $isBuilt = false; + protected bool $isBuilt = false; - public function getConfig() + public function getConfig(): InterfaceTypeConfig { if (!$this->isBuilt) { $this->isBuilt = true; @@ -35,11 +37,11 @@ public function getConfig() /** * ObjectType constructor. * - * @param $config + * @throws ConfigurationException */ - public function __construct($config = []) + public function __construct(array $config = []) { - if (empty($config)) { + if ($config === []) { $config['name'] = $this->getName(); } @@ -48,31 +50,28 @@ public function __construct($config = []) abstract public function resolveType($object); - /** - * @param InterfaceTypeConfig $config - */ - abstract public function build($config); + abstract public function build(InterfaceTypeConfig $config); - public function getKind() + public function getKind(): string { return TypeMap::KIND_INTERFACE; } - public function getNamedType() + public function getNamedType(): AbstractInterfaceType|static { return $this; } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { return is_array($value) || is_null($value) || is_object($value); } /** - * @return TypeInterface[] an array of types that implement this interface. Used mainly for introspection and + * @return TypeInterface[] an array of types that implement this interface. Used mainly for introspection and * documentation generation. */ - public function getImplementations() + public function getImplementations(): array { return []; } diff --git a/src/Type/InterfaceType/InterfaceType.php b/src/Type/InterfaceType/InterfaceType.php index 7f4154e8..9fea674f 100644 --- a/src/Type/InterfaceType/InterfaceType.php +++ b/src/Type/InterfaceType/InterfaceType.php @@ -9,24 +9,29 @@ use Youshido\GraphQL\Config\Object\InterfaceTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; final class InterfaceType extends AbstractInterfaceType { - public function __construct($config = []) + public function __construct(array $config = []) { + parent::__construct($config); $this->config = new InterfaceTypeConfig($config, $this, true); } /** * @inheritdoc - * + * * @codeCoverageIgnore */ - public function build($config) + public function build(InterfaceTypeConfig $config): void { } + /** + * @throws ConfigurationException + */ public function resolveType($object) { return $this->getConfig()->resolveType($object); diff --git a/src/Type/ListType/AbstractListType.php b/src/Type/ListType/AbstractListType.php index 94aedb37..6c6f9839 100644 --- a/src/Type/ListType/AbstractListType.php +++ b/src/Type/ListType/AbstractListType.php @@ -7,35 +7,32 @@ namespace Youshido\GraphQL\Type\ListType; - +use Exception; +use Traversable; use Youshido\GraphQL\Config\Object\ListTypeConfig; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; +use Youshido\GraphQL\Type\AbstractType; use Youshido\GraphQL\Type\CompositeTypeInterface; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\TypeMap; abstract class AbstractListType extends AbstractObjectType implements CompositeTypeInterface { - /** - * @var ListTypeConfig - */ protected $config; + /** + * @throws ConfigurationException + */ public function __construct() { + parent::__construct(); $this->config = new ListTypeConfig(['itemType' => $this->getItemType()], $this); } - /** - * @return AbstractObjectType - */ - abstract public function getItemType(); + abstract public function getItemType(): mixed; - /** - * @param mixed $value - * - * @return bool - */ - public function isValidValue($value) + public function isValidValue(mixed $value): bool { if (!$this->isIterable($value)) { return false; @@ -46,14 +43,16 @@ public function isValidValue($value) /** * @param $value - * @param bool $returnValue - * - * @return bool + * @return mixed - true/false or type of the returned value if $returnValue is true */ - protected function validList($value, $returnValue = false) + protected function validList($value, bool $returnValue = false): mixed { $itemType = $this->config->get('itemType'); + if (empty($itemType)) { + return false; + } + if ($value && $itemType->isInputType()) { foreach ($value as $item) { if (!$itemType->isValidValue($item)) { @@ -68,54 +67,60 @@ protected function validList($value, $returnValue = false) /** * @inheritdoc */ - public function build($config) + public function build(ObjectTypeConfig $config): void { } - public function isCompositeType() + public function isCompositeType(): bool { return true; } - public function getNamedType() + public function getNamedType(): mixed { return $this->getItemType(); } - final public function getKind() + final public function getKind(): string { return TypeMap::KIND_LIST; } - public function getTypeOf() + public function getTypeOf(): AbstractType { return $this->getNamedType(); } - public function parseValue($value) + /** + * @throws Exception + */ + public function parseValue($value): mixed { - foreach ((array) $value as $keyValue => $valueItem) { + foreach ((array)$value as $keyValue => $valueItem) { $value[$keyValue] = $this->getItemType()->parseValue($valueItem); } return $value; } - public function getValidationError($value = null) + public function getValidationError($value = null): ?string { if (!$this->isIterable($value)) { return 'The value is not an iterable.'; } + + if (empty($this->config->get('itemType'))) { + return 'itemType is empty.'; + } + return $this->config->get('itemType')->getValidationError($this->validList($value, true)); } /** * @param $value - * - * @return bool */ - protected function isIterable($value) + protected function isIterable($value): bool { - return null === $value || is_array($value) || ($value instanceof \Traversable); + return null === $value || is_array($value) || ($value instanceof Traversable); } } diff --git a/src/Type/ListType/ListType.php b/src/Type/ListType/ListType.php index 20244c38..cbb9b55a 100644 --- a/src/Type/ListType/ListType.php +++ b/src/Type/ListType/ListType.php @@ -10,21 +10,28 @@ use Youshido\GraphQL\Config\Object\ListTypeConfig; +use Youshido\GraphQL\Type\Enum\AbstractEnumType; +use Youshido\GraphQL\Type\InputObject\AbstractInputObjectType; +use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType; +use Youshido\GraphQL\Type\NonNullType; +use Youshido\GraphQL\Type\Object\AbstractObjectType; +use Youshido\GraphQL\Type\Scalar\AbstractScalarType; final class ListType extends AbstractListType { public function __construct($itemType) { + parent::__construct(); $this->config = new ListTypeConfig(['itemType' => $itemType], $this, true); } - public function getItemType() + public function getItemType(): mixed { return $this->getConfig()->get('itemType'); } - public function getName() + public function getName(): ?string { return null; } diff --git a/src/Type/NonNullType.php b/src/Type/NonNullType.php index abe67bf0..763efd96 100644 --- a/src/Type/NonNullType.php +++ b/src/Type/NonNullType.php @@ -16,20 +16,20 @@ final class NonNullType extends AbstractType implements CompositeTypeInterface { use ConfigAwareTrait; - private $_typeOf; + private mixed $_typeOf; /** * NonNullType constructor. * - * @param AbstractType|string $fieldType * * @throws ConfigurationException */ - public function __construct($fieldType) + public function __construct(string|AbstractType $fieldType) { if (!TypeService::isGraphQLType($fieldType)) { throw new ConfigurationException('NonNullType accepts only GraphpQL Types as argument'); } + if (TypeService::isScalarType($fieldType)) { $fieldType = TypeFactory::getScalarType($fieldType); } @@ -37,12 +37,12 @@ public function __construct($fieldType) $this->_typeOf = $fieldType; } - public function getName() + public function getName(): ?string { return null; } - public function getKind() + public function getKind(): string { return TypeMap::KIND_NON_NULL; } @@ -52,7 +52,7 @@ public function resolve($value) return $value; } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { if ($value === null) { return false; @@ -61,43 +61,42 @@ public function isValidValue($value) return $this->getNullableType()->isValidValue($value); } - public function isCompositeType() + public function isCompositeType(): bool { return true; } - public function isInputType() + public function isInputType(): bool { return true; } - public function getNamedType() + public function getNamedType(): mixed { return $this->getTypeOf(); } - public function getNullableType() + public function getNullableType(): mixed { return $this->getTypeOf(); } - public function getTypeOf() + public function getTypeOf(): mixed { return $this->_typeOf; } - public function parseValue($value) + public function parseValue($value): mixed { return $this->getNullableType()->parseValue($value); } - public function getValidationError($value = null) + public function getValidationError($value = null): ?string { if ($value === null) { return 'Field must not be NULL'; } + return $this->getNullableType()->getValidationError($value); } - - -} +} \ No newline at end of file diff --git a/src/Type/Object/AbstractMutationObjectType.php b/src/Type/Object/AbstractMutationObjectType.php index b40387ac..3d8cb570 100644 --- a/src/Type/Object/AbstractMutationObjectType.php +++ b/src/Type/Object/AbstractMutationObjectType.php @@ -7,10 +7,14 @@ namespace Youshido\GraphQL\Type\Object; +use Youshido\GraphQL\Type\InputObject\AbstractInputObjectType; +use Youshido\GraphQL\Type\NonNullType; +use Youshido\GraphQL\Type\Scalar\AbstractScalarType; + abstract class AbstractMutationObjectType extends AbstractObjectType { - public function getType() + public function getType(): NonNullType|AbstractObjectType|AbstractScalarType|AbstractInputObjectType|null|static { return $this->getOutputType(); } diff --git a/src/Type/Object/AbstractObjectType.php b/src/Type/Object/AbstractObjectType.php index 4cdc49d0..48eb339a 100644 --- a/src/Type/Object/AbstractObjectType.php +++ b/src/Type/Object/AbstractObjectType.php @@ -9,9 +9,15 @@ namespace Youshido\GraphQL\Type\Object; +use InvalidArgumentException; use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\AbstractType; +use Youshido\GraphQL\Type\InputObject\AbstractInputObjectType; +use Youshido\GraphQL\Type\Enum\AbstractEnumType; use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType; +use Youshido\GraphQL\Type\NonNullType; +use Youshido\GraphQL\Type\Scalar\AbstractScalarType; use Youshido\GraphQL\Type\Traits\AutoNameTrait; use Youshido\GraphQL\Type\Traits\FieldsArgumentsAwareObjectTrait; use Youshido\GraphQL\Type\TypeMap; @@ -22,11 +28,12 @@ */ abstract class AbstractObjectType extends AbstractType { - use AutoNameTrait, FieldsArgumentsAwareObjectTrait; + use AutoNameTrait; + use FieldsArgumentsAwareObjectTrait; - protected $isBuilt = false; + protected bool $isBuilt = false; - public function getConfig() + public function getConfig(): ObjectTypeConfig { if (!$this->isBuilt) { $this->isBuilt = true; @@ -38,54 +45,50 @@ public function getConfig() /** * ObjectType constructor. - * @param $config + * @throws ConfigurationException */ public function __construct(array $config = []) { - if (empty($config)) { - $config['name'] = $this->getName(); + if ($config === []) { + $config['name'] = $this->getName(); $config['interfaces'] = $this->getInterfaces(); } $this->config = new ObjectTypeConfig($config, $this); } - final public function serialize($value) + final public function serialize($value): mixed { - throw new \InvalidArgumentException('You can not serialize object value directly'); + throw new InvalidArgumentException('You can not serialize object value directly'); } - public function getKind() + public function getKind(): string { return TypeMap::KIND_OBJECT; } - public function getType() + public function getType(): mixed { return $this->getConfigValue('type', $this); } - public function getNamedType() + public function getNamedType(): mixed { return $this; } - /** - * @param ObjectTypeConfig $config - */ - abstract public function build($config); + abstract public function build(ObjectTypeConfig $config); /** * @return AbstractInterfaceType[] */ - public function getInterfaces() + public function getInterfaces(): array { return $this->getConfigValue('interfaces', []); } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { return is_array($value) || is_null($value) || is_object($value); } - } diff --git a/src/Type/Object/ObjectType.php b/src/Type/Object/ObjectType.php index e3692500..f9118f17 100644 --- a/src/Type/Object/ObjectType.php +++ b/src/Type/Object/ObjectType.php @@ -9,23 +9,30 @@ namespace Youshido\GraphQL\Type\Object; use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; final class ObjectType extends AbstractObjectType { + /** + * @throws ConfigurationException + */ public function __construct(array $config) { + parent::__construct($config); $this->config = new ObjectTypeConfig($config, $this, true); } /** * @inheritdoc - * + * * @codeCoverageIgnore */ - public function build($config) { } + public function build(ObjectTypeConfig $config): void + { + } - public function getName() + public function getName(): ?string { return $this->getConfigValue('name'); } diff --git a/src/Type/Scalar/AbstractScalarType.php b/src/Type/Scalar/AbstractScalarType.php index 415cad2e..6a7f8390 100644 --- a/src/Type/Scalar/AbstractScalarType.php +++ b/src/Type/Scalar/AbstractScalarType.php @@ -16,24 +16,24 @@ abstract class AbstractScalarType extends AbstractType { use ConfigAwareTrait; - public function getName() + public function getName(): string { $className = get_class($this); return substr($className, strrpos($className, '\\') + 1, -4); } - final public function getKind() + final public function getKind(): string { return TypeMap::KIND_SCALAR; } - public function parseValue($value) + public function parseValue($value): mixed { return $this->serialize($value); } - public function isInputType() + public function isInputType(): bool { return true; } diff --git a/src/Type/Scalar/BooleanType.php b/src/Type/Scalar/BooleanType.php index 8c0813c7..5c05fee2 100644 --- a/src/Type/Scalar/BooleanType.php +++ b/src/Type/Scalar/BooleanType.php @@ -11,19 +11,21 @@ class BooleanType extends AbstractScalarType { - public function getName() + public function getName(): string { return 'Boolean'; } - public function serialize($value) + public function serialize($value): ?bool { if ($value === null) { return null; } + if ($value === 'true') { return true; } + if ($value === 'false') { return false; } @@ -31,12 +33,12 @@ public function serialize($value) return (bool)$value; } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { return is_null($value) || is_bool($value); } - public function getDescription() + public function getDescription(): string { return 'The `Boolean` scalar type represents `true` or `false`.'; } diff --git a/src/Type/Scalar/DateTimeType.php b/src/Type/Scalar/DateTimeType.php index 324fa505..0a8aa088 100644 --- a/src/Type/Scalar/DateTimeType.php +++ b/src/Type/Scalar/DateTimeType.php @@ -8,6 +8,9 @@ namespace Youshido\GraphQL\Type\Scalar; +use DateTime; +use DateTimeInterface; + class DateTimeType extends AbstractScalarType { @@ -18,42 +21,42 @@ public function __construct($format = 'Y-m-d H:i:s') $this->format = $format; } - public function getName() + public function getName(): string { return 'DateTime'; } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { - if ((is_object($value) && $value instanceof \DateTimeInterface) || is_null($value)) { + if (($value instanceof DateTimeInterface) || is_null($value)) { return true; - } else if (is_string($value)) { + } elseif (is_string($value)) { $date = $this->createFromFormat($value); } else { $date = null; } - return $date ? true : false; + return (bool)$date; } - public function serialize($value) + public function serialize($value): mixed { $date = null; if (is_string($value)) { $date = $this->createFromFormat($value); - } elseif ($value instanceof \DateTimeInterface) { + } elseif ($value instanceof DateTimeInterface) { $date = $value; } return $date ? $date->format($this->format) : null; } - public function parseValue($value) + public function parseValue($value): bool|null|DateTimeInterface|DateTime { if (is_string($value)) { $date = $this->createFromFormat($value); - } elseif ($value instanceof \DateTimeInterface) { + } elseif ($value instanceof DateTimeInterface) { $date = $value; } else { $date = false; @@ -62,12 +65,12 @@ public function parseValue($value) return $date ?: null; } - private function createFromFormat($value) + private function createFromFormat(string $value): DateTime|bool { - return \DateTime::createFromFormat($this->format, $value); + return DateTime::createFromFormat($this->format, $value); } - public function getDescription() + public function getDescription(): string { return sprintf('Representation of date and time in "%s" format', $this->format); } diff --git a/src/Type/Scalar/DateTimeTzType.php b/src/Type/Scalar/DateTimeTzType.php index bdec1154..00d4929e 100644 --- a/src/Type/Scalar/DateTimeTzType.php +++ b/src/Type/Scalar/DateTimeTzType.php @@ -8,45 +8,49 @@ namespace Youshido\GraphQL\Type\Scalar; +use DateTime; +use DateTimeInterface; + class DateTimeTzType extends AbstractScalarType { - private $format = 'D, d M Y H:i:s O'; + private string $format = 'D, d M Y H:i:s O'; - public function getName() + public function getName(): string { return 'DateTimeTz'; } - public function isValidValue($value) + + public function isValidValue(mixed $value): bool { - if ((is_object($value) && $value instanceof \DateTimeInterface) || is_null($value)) { + if (($value instanceof DateTimeInterface) || is_null($value)) { return true; - } else if (is_string($value)) { + } elseif (is_string($value)) { $date = $this->createFromFormat($value); } else { $date = null; } - return $date ? true : false; + return (bool)$date; } - public function serialize($value) + public function serialize($value): mixed { $date = null; if (is_string($value)) { $date = $this->createFromFormat($value); - } elseif ($value instanceof \DateTimeInterface) { + } elseif ($value instanceof DateTimeInterface) { $date = $value; } return $date ? $date->format($this->format) : null; } - public function parseValue($value) + public function parseValue($value): bool|null|DateTimeInterface|DateTime { if (is_string($value)) { $date = $this->createFromFormat($value); - } elseif ($value instanceof \DateTimeInterface) { + } elseif ($value instanceof DateTimeInterface) { $date = $value; } else { $date = false; @@ -55,12 +59,12 @@ public function parseValue($value) return $date ?: null; } - private function createFromFormat($value) + private function createFromFormat(string $value): DateTime|bool { - return \DateTime::createFromFormat($this->format, $value); + return DateTime::createFromFormat($this->format, $value); } - public function getDescription() + public function getDescription(): string { return 'Representation of date and time in "r" format'; } diff --git a/src/Type/Scalar/DateType.php b/src/Type/Scalar/DateType.php index b37c92a5..c42dfe74 100644 --- a/src/Type/Scalar/DateType.php +++ b/src/Type/Scalar/DateType.php @@ -8,45 +8,27 @@ namespace Youshido\GraphQL\Type\Scalar; +use DateTime; + /** * @deprecated USE DateTime type instead. To be removed in 1.4. * * Class DateType * @package Youshido\GraphQL\Type\Scalar */ -class DateType extends AbstractScalarType +class DateType extends DateTimeType { - - public function getName() - { - return 'Date'; - } - - /** - * @param $value \DateTime - * @return null|string - */ - public function serialize($value) + public function __construct() { - if ($value === null) { - return null; - } - - return $value->format('Y-m-d'); + parent::__construct('Y-m-d'); } - public function isValidValue($value) + public function getName(): string { - if (is_null($value) || is_object($value)) { - return true; - } - - $d = \DateTime::createFromFormat('Y-m-d', $value); - - return $d && $d->format('Y-m-d') == $value; + return 'Date'; } - public function getDescription() + public function getDescription(): string { return 'DEPRECATED. Use DateTime instead'; } diff --git a/src/Type/Scalar/FloatType.php b/src/Type/Scalar/FloatType.php index 8aa99919..b143a7ec 100644 --- a/src/Type/Scalar/FloatType.php +++ b/src/Type/Scalar/FloatType.php @@ -11,30 +11,29 @@ class FloatType extends AbstractScalarType { - public function getName() + public function getName(): string { return 'Float'; } - public function serialize($value) + public function serialize($value): mixed { if ($value === null) { return null; } else { - return floatval($value); + return (float)$value; } } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { return is_null($value) || is_float($value) || is_int($value); } - public function getDescription() + public function getDescription(): string { - return 'The `Float` scalar type represents signed double-precision fractional ' . - 'values as specified by ' . - '[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).'; + return 'The `Float` scalar type represents signed double-precision fractional values as specified by ' . + '[IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).'; } } diff --git a/src/Type/Scalar/IdType.php b/src/Type/Scalar/IdType.php index 07e3418c..03713732 100644 --- a/src/Type/Scalar/IdType.php +++ b/src/Type/Scalar/IdType.php @@ -12,12 +12,12 @@ class IdType extends AbstractScalarType { - public function getName() + public function getName(): string { return 'ID'; } - public function serialize($value) + public function serialize($value): ?string { if (null === $value) { return null; @@ -26,12 +26,12 @@ public function serialize($value) return (string)$value; } - public function getDescription() + public function getDescription(): string { return 'The `ID` scalar type represents a unique identifier, often used to ' . - 'refetch an object or as key for a cache. The ID type appears in a JSON ' . - 'response as a String; however, it is not intended to be human-readable. ' . - 'When expected as an input type, any string (such as `"4"`) or integer ' . - '(such as `4`) input value will be accepted as an ID.'; + 'refetch an object or as key for a cache. The ID type appears in a JSON ' . + 'response as a String; however, it is not intended to be human-readable. ' . + 'When expected as an input type, any string (such as `"4"`) or integer ' . + '(such as `4`) input value will be accepted as an ID.'; } } diff --git a/src/Type/Scalar/IntType.php b/src/Type/Scalar/IntType.php index b46d8aea..2cdd5e61 100644 --- a/src/Type/Scalar/IntType.php +++ b/src/Type/Scalar/IntType.php @@ -12,37 +12,35 @@ class IntType extends AbstractScalarType { - public function getName() + public function getName(): string { return 'Int'; } - public function serialize($value) + public function serialize($value): mixed { if ($value === null) { return null; + } elseif (is_int($value)) { + return $value; } else { - if (is_int($value)) { - return $value; - } else { - $value = (int)$value; + $value = (int)$value; - return $value != 0 ? $value : null; - } + return $value !== 0 ? $value : null; } } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { return is_null($value) || is_int($value); } - public function getDescription() + public function getDescription(): string { return 'The `Int` scalar type represents non-fractional signed whole numeric ' . - 'values. Int can represent values between -(2^53 - 1) and 2^53 - 1 since ' . - 'represented in JSON as double-precision floating point numbers specified' . - 'by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).'; + 'values. Int can represent values between -(2^53 - 1) and 2^53 - 1 since ' . + 'represented in JSON as double-precision floating point numbers specified' . + 'by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).'; } } diff --git a/src/Type/Scalar/StringType.php b/src/Type/Scalar/StringType.php index 56390511..c7a345ec 100644 --- a/src/Type/Scalar/StringType.php +++ b/src/Type/Scalar/StringType.php @@ -12,12 +12,12 @@ class StringType extends AbstractScalarType { - public function getName() + public function getName(): string { return 'String'; } - public function serialize($value) + public function serialize($value): ?string { if ($value === true) { return 'true'; @@ -27,23 +27,23 @@ public function serialize($value) return null; } - if(is_array($value)) { + if (is_array($value)) { return ''; } - return (string) $value; + return (string)$value; } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { return is_null($value) || is_scalar($value) || ((is_object($value) && method_exists($value, '__toString'))); } - public function getDescription() + public function getDescription(): string { return 'The `String` scalar type represents textual data, represented as UTF-8 ' . - 'character sequences. The String type is most often used by GraphQL to ' . - 'represent free-form human-readable text.'; + 'character sequences. The String type is most often used by GraphQL to ' . + 'represent free-form human-readable text.'; } } diff --git a/src/Type/Scalar/TimestampType.php b/src/Type/Scalar/TimestampType.php index 295745f4..b490e358 100644 --- a/src/Type/Scalar/TimestampType.php +++ b/src/Type/Scalar/TimestampType.php @@ -9,6 +9,8 @@ namespace Youshido\GraphQL\Type\Scalar; +use DateTime; + /** * Class TimestampType * @package Youshido\GraphQL\Type\Scalar @@ -17,16 +19,16 @@ class TimestampType extends AbstractScalarType { - public function getName() + public function getName(): string { return 'Timestamp'; } /** - * @param $value \DateTime + * @param $value DateTime * @return null|string */ - public function serialize($value) + public function serialize($value): mixed { if ($value === null || !is_object($value)) { return null; @@ -35,7 +37,7 @@ public function serialize($value) return $value->getTimestamp(); } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { if (is_null($value) || is_object($value)) { return true; @@ -44,7 +46,7 @@ public function isValidValue($value) return is_int($value); } - public function getDescription() + public function getDescription(): string { return 'DEPRECATED. Will be converted to a real timestamp'; } diff --git a/src/Type/SchemaDirectivesList.php b/src/Type/SchemaDirectivesList.php index c79c0bd1..5562c889 100644 --- a/src/Type/SchemaDirectivesList.php +++ b/src/Type/SchemaDirectivesList.php @@ -9,23 +9,17 @@ use Youshido\GraphQL\Directive\DirectiveInterface; - class SchemaDirectivesList { - - private $directivesList = []; + private array $directivesList = []; /** - * @param array $directives * - * @throws * @return $this + * @throws */ - public function addDirectives($directives) + public function addDirectives(array $directives): static { - if (!is_array($directives)) { - throw new \Exception('addDirectives accept only array of directives'); - } foreach ($directives as $directive) { $this->addDirective($directive); } @@ -34,35 +28,31 @@ public function addDirectives($directives) } /** - * @param DirectiveInterface $directive - * * @return $this */ - public function addDirective(DirectiveInterface $directive) + public function addDirective(DirectiveInterface $directive): static { $directiveName = $this->getDirectiveName($directive); - if ($this->isDirectiveNameRegistered($directiveName)) return $this; + if ($this->isDirectiveNameRegistered($directiveName)) { + return $this; + } $this->directivesList[$directiveName] = $directive; return $this; } - private function getDirectiveName($directive) + private function getDirectiveName(DirectiveInterface $directive): string { - if (is_string($directive)) return $directive; - if (is_object($directive) && $directive instanceof DirectiveInterface) { - return $directive->getName(); - } - throw new \Exception('Invalid directive passed to Schema'); + return $directive->getName(); } - public function isDirectiveNameRegistered($directiveName) + public function isDirectiveNameRegistered($directiveName): bool { return (isset($this->directivesList[$directiveName])); } - public function getDirectives() + public function getDirectives(): array { return $this->directivesList; } diff --git a/src/Type/SchemaTypesList.php b/src/Type/SchemaTypesList.php index 2c957edc..69986d3b 100644 --- a/src/Type/SchemaTypesList.php +++ b/src/Type/SchemaTypesList.php @@ -9,56 +9,62 @@ namespace Youshido\GraphQL\Type; +use Exception; + class SchemaTypesList { - private $typesList = []; + private array $typesList = []; /** - * @param array $types - * @throws * @return $this + * @throws */ - public function addTypes($types) + public function addTypes(array $types): static { - if (!is_array($types)) { - throw new \Exception('addTypes accept only array of types'); - } - foreach($types as $type) { + foreach ($types as $type) { $this->addType($type); } + return $this; } - public function getTypes() + public function getTypes(): array { return $this->typesList; } /** - * @param TypeInterface $type * @return $this + * @throws Exception */ - public function addType(TypeInterface $type) + public function addType(TypeInterface $type): static { $typeName = $this->getTypeName($type); - if ($this->isTypeNameRegistered($typeName)) return $this; + if ($this->isTypeNameRegistered($typeName)) { + return $this; + } $this->typesList[$typeName] = $type; return $this; } - public function isTypeNameRegistered($typeName) + public function isTypeNameRegistered($typeName): bool { return (isset($this->typesList[$typeName])); } - private function getTypeName($type) { - if (is_string($type)) return $type; - if (is_object($type) && $type instanceof AbstractType) { + /** + * @throws Exception + */ + private function getTypeName(TypeInterface $type): ?string + { + + if ($type instanceof AbstractType) { return $type->getName(); } - throw new \Exception('Invalid type passed to Schema'); + + throw new Exception('Invalid type passed to Schema'); } } \ No newline at end of file diff --git a/src/Type/Traits/ArgumentsAwareObjectTrait.php b/src/Type/Traits/ArgumentsAwareObjectTrait.php index 1778690f..5469905d 100644 --- a/src/Type/Traits/ArgumentsAwareObjectTrait.php +++ b/src/Type/Traits/ArgumentsAwareObjectTrait.php @@ -9,7 +9,12 @@ namespace Youshido\GraphQL\Type\Traits; +use Youshido\GraphQL\Config\AbstractConfig; +use Youshido\GraphQL\Config\Field\FieldConfig; +use Youshido\GraphQL\Config\Field\InputFieldConfig; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Config\Traits\ConfigAwareTrait; +use Youshido\GraphQL\Field\InputField; /** * Class ArgumentsAwareObjectTrait @@ -22,32 +27,32 @@ trait ArgumentsAwareObjectTrait { use ConfigAwareTrait; - public function addArgument($argument, $argumentInfo = null) + public function addArgument($argument, $argumentInfo = null): AbstractConfig|ObjectTypeConfig|FieldConfig|InputFieldConfig { return $this->getConfig()->addArgument($argument, $argumentInfo); } - public function removeArgument($argumentName) + public function removeArgument($argumentName): AbstractConfig|ObjectTypeConfig|FieldConfig|InputFieldConfig { return $this->getConfig()->removeArgument($argumentName); } - public function getArguments() + public function getArguments(): array { return $this->getConfig()->getArguments(); } - public function getArgument($argumentName) + public function getArgument(string $argumentName): ?InputField { return $this->getConfig()->getArgument($argumentName); } - public function hasArgument($argumentName) + public function hasArgument(string $argumentName): bool { return $this->getConfig()->hasArgument($argumentName); } - public function hasArguments() + public function hasArguments(): bool { return $this->getConfig()->hasArguments(); } diff --git a/src/Type/Traits/AutoNameTrait.php b/src/Type/Traits/AutoNameTrait.php index 6c27416b..8facef5d 100644 --- a/src/Type/Traits/AutoNameTrait.php +++ b/src/Type/Traits/AutoNameTrait.php @@ -7,6 +7,7 @@ */ namespace Youshido\GraphQL\Type\Traits; + use Youshido\GraphQL\Field\FieldInterface; /** @@ -15,10 +16,9 @@ */ trait AutoNameTrait { - - public function getName() + public function getName(): ?string { - if (!empty($this->config)) { + if (!empty($this->config?->getName())) { return $this->config->getName(); } @@ -27,9 +27,10 @@ public function getName() if ($prevPos = strrpos($className, '\\')) { $className = substr($className, $prevPos + 1); } - if (substr($className, -5) == 'Field') { + + if (str_ends_with($className, 'Field')) { $className = lcfirst(substr($className, 0, -5)); - } elseif (substr($className, -4) == 'Type') { + } elseif (str_ends_with($className, 'Type')) { $className = substr($className, 0, -4); } @@ -37,8 +38,6 @@ public function getName() $className = lcfirst($className); } - return $className; } - -} +} \ No newline at end of file diff --git a/src/Type/Traits/FieldsArgumentsAwareObjectTrait.php b/src/Type/Traits/FieldsArgumentsAwareObjectTrait.php index 0a613a60..9ffd3b1e 100644 --- a/src/Type/Traits/FieldsArgumentsAwareObjectTrait.php +++ b/src/Type/Traits/FieldsArgumentsAwareObjectTrait.php @@ -9,44 +9,51 @@ namespace Youshido\GraphQL\Type\Traits; +use Youshido\GraphQL\Config\AbstractConfig; +use Youshido\GraphQL\Config\Field\FieldConfig; +use Youshido\GraphQL\Config\Field\InputFieldConfig; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Field\InputField; +use Youshido\GraphQL\Parser\Ast\Argument; + trait FieldsArgumentsAwareObjectTrait { use FieldsAwareObjectTrait; - protected $hasArgumentCache = null; + protected bool $hasArgumentCache = false; - public function addArguments($argumentsList) + public function addArguments($argumentsList): AbstractConfig|ObjectTypeConfig|FieldConfig|InputFieldConfig { return $this->getConfig()->addArguments($argumentsList); } - public function removeArgument($argumentName) + public function removeArgument($argumentName): AbstractConfig|ObjectTypeConfig|FieldConfig|InputFieldConfig { return $this->getConfig()->removeArgument($argumentName); } - public function addArgument($argument, $ArgumentInfo = null) + public function addArgument($argument, $ArgumentInfo = null): AbstractConfig|ObjectTypeConfig|FieldConfig|InputFieldConfig { return $this->getConfig()->addArgument($argument, $ArgumentInfo); } - public function getArguments() + public function getArguments(): array { return $this->getConfig()->getArguments(); } - public function getArgument($argumentName) + public function getArgument(string $argumentName): InputField { return $this->getConfig()->getArgument($argumentName); } - public function hasArgument($argumentName) + public function hasArgument(string $argumentName): bool { return $this->getConfig()->hasArgument($argumentName); } - public function hasArguments() + public function hasArguments(): bool { - return $this->hasArgumentCache === null ? ($this->hasArgumentCache = $this->getConfig()->hasArguments()) : $this->hasArgumentCache; + return empty($this->hasArgumentCache) ? ($this->hasArgumentCache = $this->getConfig()->hasArguments()) : $this->hasArgumentCache; } } diff --git a/src/Type/Traits/FieldsAwareObjectTrait.php b/src/Type/Traits/FieldsAwareObjectTrait.php index e05ad69d..57d0b2cd 100644 --- a/src/Type/Traits/FieldsAwareObjectTrait.php +++ b/src/Type/Traits/FieldsAwareObjectTrait.php @@ -10,26 +10,33 @@ use Youshido\GraphQL\Config\Traits\ConfigAwareTrait; +use Youshido\GraphQL\Exception\ConfigurationException; trait FieldsAwareObjectTrait { use ConfigAwareTrait; - public function addFields($fieldsList) + /** + * @throws ConfigurationException + */ + public function addFields($fieldsList): static { $this->getConfig()->addFields($fieldsList); return $this; } - public function addField($field, $fieldInfo = null) + /** + * @throws ConfigurationException + */ + public function addField($field, $fieldInfo = null): static { $this->getConfig()->addField($field, $fieldInfo); return $this; } - public function getFields() + public function getFields(): array { return $this->getConfig()->getFields(); } @@ -39,14 +46,13 @@ public function getField($fieldName) return $this->getConfig()->getField($fieldName); } - public function hasField($fieldName) + public function hasField($fieldName): bool { return $this->getConfig()->hasField($fieldName); } - public function hasFields() + public function hasFields(): bool { return $this->getConfig()->hasFields(); } - -} +} \ No newline at end of file diff --git a/src/Type/TypeFactory.php b/src/Type/TypeFactory.php index 25f2550b..b4f46aaf 100644 --- a/src/Type/TypeFactory.php +++ b/src/Type/TypeFactory.php @@ -8,33 +8,37 @@ namespace Youshido\GraphQL\Type; - use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\Scalar\AbstractScalarType; class TypeFactory { - private static $objectsHash = []; + private static array $objectsHash = []; /** - * @param string $type * * @throws ConfigurationException - * @return AbstractScalarType */ - public static function getScalarType($type) + public static function getScalarType(string $type): ?AbstractScalarType { if (TypeService::isScalarType($type)) { - if (is_object($type)) { - return $type; - } if (empty(self::$objectsHash[$type])) { $name = ucfirst($type); - $name = $name == 'Datetime' ? 'DateTime' : $name; - $name = $name == 'Datetimetz' ? 'DateTimeTz' : $name; + $name = $name === 'Datetime' ? 'DateTime' : $name; + $name = $name === 'Datetimetz' ? 'DateTimeTz' : $name; + + $className = 'Youshido\GraphQL\Type\Scalar\\' . $name . 'Type'; + + // Hotfix for our custom app - TODO - add via configuration + if (in_array($name, ['DateTimeAsString', 'StringOrArray', 'Boolean', 'Float', 'Int'])) { + $className = 'App\GraphQL\Schema\Type\Scalar\\' . $name . 'Type'; + // Fallback to base scalar types if custom doesn't exist + if (!class_exists($className)) { + $className = 'Youshido\GraphQL\Type\Scalar\\' . $name . 'Type'; + } + } - $className = 'Youshido\GraphQL\Type\Scalar\\' . $name . 'Type'; self::$objectsHash[$type] = new $className(); } @@ -47,7 +51,7 @@ public static function getScalarType($type) /** * @return string[] */ - public static function getScalarTypesNames() + public static function getScalarTypesNames(): array { return [ TypeMap::TYPE_INT, @@ -59,6 +63,8 @@ public static function getScalarTypesNames() TypeMap::TYPE_DATE, TypeMap::TYPE_TIMESTAMP, TypeMap::TYPE_DATETIMETZ, + TypeMap::TYPE_DATETIME_AS_STRING, + TypeMap::TYPE_STRING_OR_ARRAY ]; } } diff --git a/src/Type/TypeInterface.php b/src/Type/TypeInterface.php index 5688b32c..04740333 100644 --- a/src/Type/TypeInterface.php +++ b/src/Type/TypeInterface.php @@ -8,7 +8,7 @@ namespace Youshido\GraphQL\Type; -Interface TypeInterface extends InputTypeInterface +interface TypeInterface extends InputTypeInterface { } \ No newline at end of file diff --git a/src/Type/TypeMap.php b/src/Type/TypeMap.php index 336b2fbd..d622d190 100644 --- a/src/Type/TypeMap.php +++ b/src/Type/TypeMap.php @@ -10,25 +10,41 @@ class TypeMap { + final const KIND_SCALAR = 'SCALAR'; - const KIND_SCALAR = 'SCALAR'; - const KIND_OBJECT = 'OBJECT'; - const KIND_INTERFACE = 'INTERFACE'; - const KIND_UNION = 'UNION'; - const KIND_ENUM = 'ENUM'; - const KIND_INPUT_OBJECT = 'INPUT_OBJECT'; - const KIND_LIST = 'LIST'; - const KIND_NON_NULL = 'NON_NULL'; - - const TYPE_INT = 'int'; - const TYPE_FLOAT = 'float'; - const TYPE_STRING = 'string'; - const TYPE_BOOLEAN = 'boolean'; - const TYPE_ID = 'id'; - const TYPE_DATETIME = 'datetime'; - const TYPE_DATETIMETZ = 'datetimetz'; - const TYPE_DATE = 'date'; - const TYPE_TIMESTAMP = 'timestamp'; + final const KIND_OBJECT = 'OBJECT'; + final const KIND_INTERFACE = 'INTERFACE'; + final const KIND_UNION = 'UNION'; + + final const KIND_ENUM = 'ENUM'; + + final const KIND_INPUT_OBJECT = 'INPUT_OBJECT'; + + final const KIND_LIST = 'LIST'; + + final const KIND_NON_NULL = 'NON_NULL'; + + final const TYPE_INT = 'int'; + + final const TYPE_FLOAT = 'float'; + + final const TYPE_STRING = 'string'; + + final const TYPE_BOOLEAN = 'boolean'; + + final const TYPE_ID = 'id'; + + final const TYPE_DATETIME = 'datetime'; + + final const TYPE_DATETIMETZ = 'datetimetz'; + + final const TYPE_DATETIME_AS_STRING = 'datetimeasstring'; + + final const TYPE_DATE = 'date'; + + final const TYPE_TIMESTAMP = 'timestamp'; + + final const TYPE_STRING_OR_ARRAY = 'stringorarray'; } diff --git a/src/Type/TypeService.php b/src/Type/TypeService.php index cb1a29cf..9e89d1fe 100644 --- a/src/Type/TypeService.php +++ b/src/Type/TypeService.php @@ -9,6 +9,7 @@ namespace Youshido\GraphQL\Type; +use Exception; use Symfony\Component\PropertyAccess\PropertyAccess; use Youshido\GraphQL\Type\Enum\AbstractEnumType; use Youshido\GraphQL\Type\InputObject\AbstractInputObjectType; @@ -20,23 +21,41 @@ class TypeService { - const TYPE_CALLABLE = 'callable'; - const TYPE_GRAPHQL_TYPE = 'graphql_type'; - const TYPE_OBJECT_TYPE = 'object_type'; - const TYPE_ARRAY_OF_OBJECT_TYPES = 'array_of_object_types'; - const TYPE_OBJECT_INPUT_TYPE = 'object_input_type'; - const TYPE_LIST = 'list'; - const TYPE_BOOLEAN = TypeMap::TYPE_BOOLEAN; - const TYPE_STRING = TypeMap::TYPE_STRING; - const TYPE_ARRAY = 'array'; - const TYPE_ARRAY_OF_FIELDS_CONFIG = 'array_of_fields'; - const TYPE_ARRAY_OF_INPUT_FIELDS = 'array_of_inputs'; - const TYPE_ENUM_VALUES = 'array_of_values'; - const TYPE_ARRAY_OF_INTERFACES = 'array_of_interfaces'; - const TYPE_ANY = 'any'; - const TYPE_ANY_OBJECT = 'any_object'; - const TYPE_ANY_INPUT = 'any_input'; + final const TYPE_CALLABLE = 'callable'; + final const TYPE_GRAPHQL_TYPE = 'graphql_type'; + + final const TYPE_OBJECT_TYPE = 'object_type'; + + final const TYPE_ARRAY_OF_OBJECT_TYPES = 'array_of_object_types'; + + final const TYPE_OBJECT_INPUT_TYPE = 'object_input_type'; + + final const TYPE_LIST = 'list'; + + final const TYPE_BOOLEAN = TypeMap::TYPE_BOOLEAN; + + final const TYPE_STRING = TypeMap::TYPE_STRING; + + final const TYPE_ARRAY = 'array'; + + final const TYPE_ARRAY_OF_FIELDS_CONFIG = 'array_of_fields'; + + final const TYPE_ARRAY_OF_INPUT_FIELDS = 'array_of_inputs'; + + final const TYPE_ENUM_VALUES = 'array_of_values'; + + final const TYPE_ARRAY_OF_INTERFACES = 'array_of_interfaces'; + + final const TYPE_ANY = 'any'; + + final const TYPE_ANY_OBJECT = 'any_object'; + + final const TYPE_ANY_INPUT = 'any_input'; + + /** + * @throws Exception + */ public static function resolveNamedType($object) { if (is_object($object)) { @@ -49,14 +68,13 @@ public static function resolveNamedType($object) return new StringType(); } - throw new \Exception('Invalid type'); + throw new Exception('Invalid type'); } /** * @param AbstractType|mixed $type - * @return bool */ - public static function isInterface($type) + public static function isInterface(mixed $type): bool { if (!is_object($type)) { return false; @@ -67,9 +85,8 @@ public static function isInterface($type) /** * @param AbstractType|mixed $type - * @return bool */ - public static function isAbstractType($type) + public static function isAbstractType(mixed $type): bool { if (!is_object($type)) { return false; @@ -78,65 +95,62 @@ public static function isAbstractType($type) return in_array($type->getKind(), [TypeMap::KIND_INTERFACE, TypeMap::KIND_UNION]); } - public static function isScalarType($type) + public static function isScalarType($type): bool { if (is_object($type)) { - return $type instanceof AbstractScalarType || $type instanceof AbstractEnumType; + return $type instanceof AbstractScalarType; } - return in_array(strtolower($type), TypeFactory::getScalarTypesNames()); + return in_array(strtolower((string)$type), TypeFactory::getScalarTypesNames()); } - public static function isGraphQLType($type) + public static function isGraphQLType($type): bool { return $type instanceof AbstractType || TypeService::isScalarType($type); } - public static function isLeafType($type) + public static function isLeafType($type): bool { return $type instanceof AbstractEnumType || TypeService::isScalarType($type); } - public static function isObjectType($type) + public static function isObjectType($type): bool { return $type instanceof AbstractObjectType; } /** * @param mixed|AbstractType $type - * @return bool */ - public static function isInputType($type) + public static function isInputType(mixed $type): bool { if (is_object($type)) { $namedType = $type->getNullableType()->getNamedType(); return ($namedType instanceof AbstractScalarType) - || ($type instanceof AbstractListType) - || ($namedType instanceof AbstractInputObjectType) - || ($namedType instanceof AbstractEnumType); + || ($type instanceof AbstractListType) + || ($namedType instanceof AbstractInputObjectType) + || ($namedType instanceof AbstractEnumType); } else { return TypeService::isScalarType($type); } } - public static function isInputObjectType($type) + public static function isInputObjectType($type): bool { return $type instanceof AbstractInputObjectType; } /** - * @param object|array $data - * @param string $path - * @param bool $enableMagicCall whether to attempt to resolve properties using __call() + * @param bool $enableMagicCall whether to attempt to resolve properties using __call() * * @return mixed|null */ - public static function getPropertyValue($data, $path, $enableMagicCall = false) + public static function getPropertyValue(object|array $data, string $path, bool $enableMagicCall = false): mixed { // Normalize the path if (is_array($data)) { - $path = "[$path]"; + $path = sprintf('[%s]', $path); } // Optionally enable __call() support @@ -150,4 +164,4 @@ public static function getPropertyValue($data, $path, $enableMagicCall = false) return $propertyAccessor->isReadable($data, $path) ? $propertyAccessor->getValue($data, $path) : null; } -} +} \ No newline at end of file diff --git a/src/Type/Union/AbstractUnionType.php b/src/Type/Union/AbstractUnionType.php index 1b3c3410..267811a8 100644 --- a/src/Type/Union/AbstractUnionType.php +++ b/src/Type/Union/AbstractUnionType.php @@ -11,8 +11,12 @@ use Youshido\GraphQL\Config\Object\UnionTypeConfig; use Youshido\GraphQL\Config\Traits\ConfigAwareTrait; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Type\AbstractInterfaceTypeInterface; use Youshido\GraphQL\Type\AbstractType; +use Youshido\GraphQL\Type\InputObject\AbstractInputObjectType; +use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType; +use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Scalar\AbstractScalarType; use Youshido\GraphQL\Type\Traits\AutoNameTrait; @@ -21,18 +25,19 @@ abstract class AbstractUnionType extends AbstractType implements AbstractInterfaceTypeInterface { - use ConfigAwareTrait, AutoNameTrait; + use ConfigAwareTrait; + use AutoNameTrait; - protected $isFinal = false; + protected bool $isFinal = false; /** * ObjectType constructor. - * @param $config + * @throws ConfigurationException */ - public function __construct($config = []) + public function __construct(array $config = []) { - if (empty($config)) { - $config['name'] = $this->getName(); + if ($config === []) { + $config['name'] = $this->getName(); $config['types'] = $this->getTypes(); } @@ -42,19 +47,19 @@ public function __construct($config = []) /** * @return AbstractObjectType[]|AbstractScalarType[] */ - abstract public function getTypes(); + abstract public function getTypes(): array; - public function getKind() + public function getKind(): string { return TypeMap::KIND_UNION; } - public function getNamedType() + public function getNamedType(): AbstractUnionType|static { return $this; } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { return true; } diff --git a/src/Type/Union/UnionType.php b/src/Type/Union/UnionType.php index f419159b..1e737cd0 100644 --- a/src/Type/Union/UnionType.php +++ b/src/Type/Union/UnionType.php @@ -8,19 +8,21 @@ namespace Youshido\GraphQL\Type\Union; +use Youshido\GraphQL\Type\AbstractType; + final class UnionType extends AbstractUnionType { - protected $isFinal = true; + protected bool $isFinal = true; - public function resolveType($object) + public function resolveType(object $object): ?AbstractType { $callable = $this->getConfigValue('resolveType'); return $callable($object); } - public function getTypes() + public function getTypes(): array { return $this->getConfig()->get('types', []); } diff --git a/src/Validator/ConfigValidator/ConfigValidator.php b/src/Validator/ConfigValidator/ConfigValidator.php index 9cd7957d..9454a08b 100644 --- a/src/Validator/ConfigValidator/ConfigValidator.php +++ b/src/Validator/ConfigValidator/ConfigValidator.php @@ -36,10 +36,7 @@ private function __construct() $this->initializeRules(); } - /** - * @return ConfigValidator - */ - public static function getInstance() + public static function getInstance(): ConfigValidator { if (empty(self::$instance)) { self::$instance = new self(); @@ -50,19 +47,22 @@ public static function getInstance() return self::$instance; } - public function assertValidConfig(AbstractConfig $config) + /** + * @throws ConfigurationException + */ + public function assertValidConfig(AbstractConfig $config): void { if (!$this->isValidConfig($config)) { throw new ConfigurationException('Config is not valid for ' . ($config->getContextObject() ? get_class($config->getContextObject()) : null) . "\n" . implode("\n", $this->getErrorsArray(false))); } } - public function isValidConfig(AbstractConfig $config) + public function isValidConfig(AbstractConfig $config): bool { return $this->validate($config->getData(), $this->getConfigFinalRules($config), $config->isExtraFieldsAllowed()); } - protected function getConfigFinalRules(AbstractConfig $config) + protected function getConfigFinalRules(AbstractConfig $config): array { $rules = $config->getRules(); if ($config->isFinalClass()) { @@ -77,9 +77,11 @@ protected function getConfigFinalRules(AbstractConfig $config) } - public function validate($data, $rules = [], $extraFieldsAllowed = null) + public function validate($data, $rules = [], $extraFieldsAllowed = null): bool { - if ($extraFieldsAllowed !== null) $this->setExtraFieldsAllowed($extraFieldsAllowed); + if ($extraFieldsAllowed !== null) { + $this->setExtraFieldsAllowed($extraFieldsAllowed); + } $processedFields = []; foreach ($rules as $fieldName => $fieldRules) { @@ -97,7 +99,10 @@ public function validate($data, $rules = [], $extraFieldsAllowed = null) } elseif (!array_key_exists($fieldName, $data)) { continue; } - if (!empty($fieldRules['final'])) unset($fieldRules['final']); + + if (!empty($fieldRules['final'])) { + unset($fieldRules['final']); + } /** Validation of all other rules*/ foreach ($fieldRules as $ruleName => $ruleInfo) { @@ -124,36 +129,31 @@ public function validate($data, $rules = [], $extraFieldsAllowed = null) return $this->isValid(); } - protected function initializeRules() + protected function initializeRules(): void { $this->validationRules['type'] = new TypeValidationRule($this); } - public function addRule($name, ValidationRuleInterface $rule) + public function addRule($name, ValidationRuleInterface $rule): void { $this->validationRules[$name] = $rule; } - public function isValid() + public function isValid(): bool { return !$this->hasErrors(); } - /** - * @return boolean - */ - public function isExtraFieldsAllowed() + public function isExtraFieldsAllowed(): bool { return $this->extraFieldsAllowed; } /** * @param boolean $extraFieldsAllowed - * - * @return ConfigValidator */ - public function setExtraFieldsAllowed($extraFieldsAllowed) + public function setExtraFieldsAllowed($extraFieldsAllowed): static { $this->extraFieldsAllowed = $extraFieldsAllowed; diff --git a/src/Validator/ConfigValidator/ConfigValidatorInterface.php b/src/Validator/ConfigValidator/ConfigValidatorInterface.php index 1b3d2adf..744f2204 100644 --- a/src/Validator/ConfigValidator/ConfigValidatorInterface.php +++ b/src/Validator/ConfigValidator/ConfigValidatorInterface.php @@ -11,6 +11,6 @@ interface ConfigValidatorInterface { - public function validate($data, $rules = [], $allowExtraFields = null); + public function validate($data, $rules = [], $allowAllowAllowExtraFields = null); } diff --git a/src/Validator/ConfigValidator/Rules/TypeValidationRule.php b/src/Validator/ConfigValidator/Rules/TypeValidationRule.php index 1b068f61..1a53bf20 100644 --- a/src/Validator/ConfigValidator/Rules/TypeValidationRule.php +++ b/src/Validator/ConfigValidator/Rules/TypeValidationRule.php @@ -9,6 +9,7 @@ namespace Youshido\GraphQL\Validator\ConfigValidator\Rules; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Field\FieldInterface; use Youshido\GraphQL\Field\InputFieldInterface; use Youshido\GraphQL\Type\AbstractType; @@ -18,72 +19,45 @@ class TypeValidationRule implements ValidationRuleInterface { - - private $configValidator; + private readonly ConfigValidator $configValidator; public function __construct(ConfigValidator $validator) { $this->configValidator = $validator; } - public function validate($data, $ruleInfo) + /** + * @throws ConfigurationException + */ + public function validate($data, $ruleInfo): bool { - if (!is_string($ruleInfo)) return false; - - switch ($ruleInfo) { - case TypeService::TYPE_ANY: - return true; - - case TypeService::TYPE_ANY_OBJECT: - return is_object($data); - - case TypeService::TYPE_CALLABLE: - return is_callable($data); - - case TypeService::TYPE_BOOLEAN: - return is_bool($data); - - case TypeService::TYPE_ARRAY: - return is_array($data); - - case TypeService::TYPE_STRING: - return TypeFactory::getScalarType($ruleInfo)->isValidValue($data); - - case TypeService::TYPE_GRAPHQL_TYPE: - return TypeService::isGraphQLType($data); - - case TypeService::TYPE_OBJECT_TYPE: - return TypeService::isObjectType($data); - - case TypeService::TYPE_ARRAY_OF_OBJECT_TYPES: - return $this->isArrayOfObjectTypes($data); - - case TypeService::TYPE_ARRAY_OF_FIELDS_CONFIG: - return $this->isArrayOfFields($data); - - case TypeService::TYPE_OBJECT_INPUT_TYPE: - return TypeService::isInputObjectType($data); - - case TypeService::TYPE_ENUM_VALUES: - return $this->isEnumValues($data); - - case TypeService::TYPE_ARRAY_OF_INPUT_FIELDS: - return $this->isArrayOfInputFields($data); - - case TypeService::TYPE_ANY_INPUT: - return TypeService::isInputType($data); - - case TypeService::TYPE_ARRAY_OF_INTERFACES: - return $this->isArrayOfInterfaces($data); - - default: - return false; + if (!is_string($ruleInfo)) { + return false; } + + return match ($ruleInfo) { + TypeService::TYPE_ANY => true, + TypeService::TYPE_ANY_OBJECT => is_object($data), + TypeService::TYPE_CALLABLE => is_callable($data), + TypeService::TYPE_BOOLEAN => is_bool($data), + TypeService::TYPE_ARRAY => is_array($data), + TypeService::TYPE_STRING => TypeFactory::getScalarType($ruleInfo)->isValidValue($data), + TypeService::TYPE_GRAPHQL_TYPE => TypeService::isGraphQLType($data), + TypeService::TYPE_OBJECT_TYPE => TypeService::isObjectType($data), + TypeService::TYPE_ARRAY_OF_OBJECT_TYPES => $this->isArrayOfObjectTypes($data), + TypeService::TYPE_ARRAY_OF_FIELDS_CONFIG => $this->isArrayOfFields($data), + TypeService::TYPE_OBJECT_INPUT_TYPE => TypeService::isInputObjectType($data), + TypeService::TYPE_ENUM_VALUES => $this->isEnumValues($data), + TypeService::TYPE_ARRAY_OF_INPUT_FIELDS => $this->isArrayOfInputFields($data), + TypeService::TYPE_ANY_INPUT => TypeService::isInputType($data), + TypeService::TYPE_ARRAY_OF_INTERFACES => $this->isArrayOfInterfaces($data), + default => false, + }; } - private function isArrayOfObjectTypes($data) + private function isArrayOfObjectTypes($data): bool { - if (!is_array($data) || !count($data)) { + if (!is_array($data) || $data === []) { return false; } @@ -96,9 +70,11 @@ private function isArrayOfObjectTypes($data) return true; } - private function isEnumValues($data) + private function isEnumValues($data): bool { - if (!is_array($data) || empty($data)) return false; + if (!is_array($data) || $data === []) { + return false; + } foreach ($data as $item) { if (!is_array($item) || !array_key_exists('name', $item) || !is_string($item['name']) || !preg_match('/^[_a-zA-Z][_a-zA-Z0-9]*$/', $item['name'])) { @@ -113,9 +89,11 @@ private function isEnumValues($data) return true; } - private static function isArrayOfInterfaces($data) + private function isArrayOfInterfaces($data): bool { - if (!is_array($data)) return false; + if (!is_array($data)) { + return false; + } foreach ($data as $item) { if (!TypeService::isInterface($item)) { @@ -126,18 +104,22 @@ private static function isArrayOfInterfaces($data) return true; } - private function isArrayOfFields($data) + private function isArrayOfFields($data): bool { - if (!is_array($data) || empty($data)) return false; + if (!is_array($data) || $data === []) { + return false; + } foreach ($data as $name => $item) { - if (!$this->isField($item, $name)) return false; + if (!$this->isField($item, $name)) { + return false; + } } return true; } - private function isField($data, $name = null) + private function isField($data, $name = null): bool { if (is_object($data)) { if (($data instanceof FieldInterface) || ($data instanceof AbstractType)) { @@ -146,6 +128,7 @@ private function isField($data, $name = null) return false; } } + if (!is_array($data)) { $data = [ 'type' => $data, @@ -154,23 +137,28 @@ private function isField($data, $name = null) } elseif (empty($data['name'])) { $data['name'] = $name; } + $this->configValidator->validate($data, $this->getFieldConfigRules()); return $this->configValidator->isValid(); } - private function isArrayOfInputFields($data) + private function isArrayOfInputFields($data): bool { - if (!is_array($data)) return false; + if (!is_array($data)) { + return false; + } - foreach ($data as $name => $item) { - if (!$this->isInputField($item)) return false; + foreach ($data as $item) { + if (!$this->isInputField($item)) { + return false; + } } return true; } - private function isInputField($data) + private function isInputField(array $data): bool { if (is_object($data)) { if ($data instanceof InputFieldInterface) { @@ -189,20 +177,18 @@ private function isInputField($data) /** * Exists for the performance - * @return array */ - private function getFieldConfigRules() + private function getFieldConfigRules(): array { return [ - 'name' => ['type' => TypeService::TYPE_STRING, 'required' => true], - 'type' => ['type' => TypeService::TYPE_ANY, 'required' => true], - 'args' => ['type' => TypeService::TYPE_ARRAY], - 'description' => ['type' => TypeService::TYPE_STRING], - 'resolve' => ['type' => TypeService::TYPE_CALLABLE], - 'isDeprecated' => ['type' => TypeService::TYPE_BOOLEAN], + 'name' => ['type' => TypeService::TYPE_STRING, 'required' => true], + 'type' => ['type' => TypeService::TYPE_ANY, 'required' => true], + 'args' => ['type' => TypeService::TYPE_ARRAY], + 'description' => ['type' => TypeService::TYPE_STRING], + 'resolve' => ['type' => TypeService::TYPE_CALLABLE], + 'isDeprecated' => ['type' => TypeService::TYPE_BOOLEAN], 'deprecationReason' => ['type' => TypeService::TYPE_STRING], - 'cost' => ['type' => TypeService::TYPE_ANY] + 'cost' => ['type' => TypeService::TYPE_ANY] ]; } - -} +} \ No newline at end of file diff --git a/src/Validator/ErrorContainer/ErrorContainerInterface.php b/src/Validator/ErrorContainer/ErrorContainerInterface.php index 7da1dc8f..ec9d8087 100644 --- a/src/Validator/ErrorContainer/ErrorContainerInterface.php +++ b/src/Validator/ErrorContainer/ErrorContainerInterface.php @@ -8,15 +8,19 @@ namespace Youshido\GraphQL\Validator\ErrorContainer; +use Exception; + interface ErrorContainerInterface { - public function addError(\Exception $exception); + public function addError(Exception $exception); public function mergeErrors(ErrorContainerInterface $errorContainer); public function hasErrors(); + public function hasError(Exception $exception); + public function getErrors(); public function getErrorsArray(); diff --git a/src/Validator/ErrorContainer/ErrorContainerTrait.php b/src/Validator/ErrorContainer/ErrorContainerTrait.php index 93bc3b22..3d17647a 100644 --- a/src/Validator/ErrorContainer/ErrorContainerTrait.php +++ b/src/Validator/ErrorContainer/ErrorContainerTrait.php @@ -7,33 +7,40 @@ namespace Youshido\GraphQL\Validator\ErrorContainer; +use Exception; use Youshido\GraphQL\Exception\Interfaces\ExtendedExceptionInterface; use Youshido\GraphQL\Exception\Interfaces\LocationableExceptionInterface; trait ErrorContainerTrait { + /** @var Exception[] */ + protected array $errors = []; - /** @var \Exception[] */ - protected $errors = []; - - public function addError(\Exception $exception) + public function addError(Exception $exception): static { - $this->errors[] = $exception; + if (!$this->hasError($exception)) { + $this->errors[] = $exception; + } return $this; } - public function hasErrors() + public function hasErrors(): bool + { + return !empty($this->errors); + } + + public function hasError(Exception $exception): bool { - return ! empty($this->errors); + return $this->hasErrors() && in_array($exception, $this->errors); } - public function getErrors() + public function getErrors(): array { return $this->errors; } - public function mergeErrors(ErrorContainerInterface $errorContainer) + public function mergeErrors(ErrorContainerInterface $errorContainer): static { if ($errorContainer->hasErrors()) { foreach ($errorContainer->getErrors() as $error) { @@ -44,7 +51,7 @@ public function mergeErrors(ErrorContainerInterface $errorContainer) return $this; } - public function getErrorsArray($inGraphQLStyle = true) + public function getErrorsArray(bool $inGraphQLStyle = true): array { $errors = []; @@ -79,11 +86,10 @@ public function getErrorsArray($inGraphQLStyle = true) return $errors; } - public function clearErrors() + public function clearErrors(): static { $this->errors = []; return $this; } - } diff --git a/src/Validator/RequestValidator/RequestValidator.php b/src/Validator/RequestValidator/RequestValidator.php index 457afb28..26c2a40c 100644 --- a/src/Validator/RequestValidator/RequestValidator.php +++ b/src/Validator/RequestValidator/RequestValidator.php @@ -10,11 +10,15 @@ use Youshido\GraphQL\Exception\Parser\InvalidRequestException; use Youshido\GraphQL\Execution\Request; +use Youshido\GraphQL\Parser\Ast\Fragment; class RequestValidator implements RequestValidatorInterface { - public function validate(Request $request) + /** + * @throws InvalidRequestException + */ + public function validate(Request $request): void { $this->assertFragmentReferencesValid($request); $this->assetFragmentsUsed($request); @@ -22,7 +26,10 @@ public function validate(Request $request) $this->assertAllVariablesUsed($request); } - private function assetFragmentsUsed(Request $request) + /** + * @throws InvalidRequestException + */ + private function assetFragmentsUsed(Request $request): void { foreach ($request->getFragmentReferences() as $fragmentReference) { $request->getFragment($fragmentReference->getName())->setUsed(true); @@ -35,16 +42,22 @@ private function assetFragmentsUsed(Request $request) } } - private function assertFragmentReferencesValid(Request $request) + /** + * @throws InvalidRequestException + */ + private function assertFragmentReferencesValid(Request $request): void { foreach ($request->getFragmentReferences() as $fragmentReference) { - if (!$request->getFragment($fragmentReference->getName())) { + if (!$request->getFragment($fragmentReference->getName()) instanceof Fragment) { throw new InvalidRequestException(sprintf('Fragment "%s" not defined in query', $fragmentReference->getName()), $fragmentReference->getLocation()); } } } - private function assertAllVariablesExists(Request $request) + /** + * @throws InvalidRequestException + */ + private function assertAllVariablesExists(Request $request): void { foreach ($request->getVariableReferences() as $variableReference) { if (!$variableReference->getVariable()) { @@ -53,7 +66,10 @@ private function assertAllVariablesExists(Request $request) } } - private function assertAllVariablesUsed(Request $request) + /** + * @throws InvalidRequestException + */ + private function assertAllVariablesUsed(Request $request): void { foreach ($request->getQueryVariables() as $queryVariable) { if (!$queryVariable->isUsed()) { diff --git a/src/Validator/ResolveValidator/ResolveValidator.php b/src/Validator/ResolveValidator/ResolveValidator.php index ab7e3963..9c2aa6c4 100644 --- a/src/Validator/ResolveValidator/ResolveValidator.php +++ b/src/Validator/ResolveValidator/ResolveValidator.php @@ -24,38 +24,41 @@ class ResolveValidator implements ResolveValidatorInterface { - /** @var ExecutionContext */ - private $executionContext; + private readonly ExecutionContext $executionContext; /** * ResolveValidator constructor. - * - * @param ExecutionContext $executionContext */ public function __construct(ExecutionContext $executionContext) { $this->executionContext = $executionContext; } - - public function assetTypeHasField(AbstractType $objectType, AstFieldInterface $ast) + + /** + * @throws ResolveException + */ + public function assetTypeHasField(AbstractType $objectType, AstFieldInterface $ast): void { /** @var AbstractObjectType $objectType */ if ($this->executionContext->getField($objectType, $ast->getName()) !== null) { return; } - - if (!(TypeService::isObjectType($objectType) || TypeService::isInputObjectType($objectType)) || !$objectType->hasField($ast->getName())) { - $availableFieldNames = implode(', ', array_map(function (FieldInterface $field) { + + if (!TypeService::isObjectType($objectType) && !TypeService::isInputObjectType($objectType) || !$objectType->hasField($ast->getName())) { + $availableFieldNames = implode(', ', array_map(static function (FieldInterface $field): string { return sprintf('"%s"', $field->getName()); }, $objectType->getFields())); throw new ResolveException(sprintf('Field "%s" not found in type "%s". Available fields are: %s', $ast->getName(), $objectType->getNamedType()->getName(), $availableFieldNames), $ast->getLocation()); } } - public function assertValidArguments(FieldInterface $field, AstFieldInterface $query, Request $request) + /** + * @throws ResolveException + */ + public function assertValidArguments(FieldInterface $field, AstFieldInterface $query, Request $request): void { - $requiredArguments = array_filter($field->getArguments(), function (InputField $argument) { + $requiredArguments = array_filter($field->getArguments(), static function (InputField $argument): bool { return $argument->getType()->getKind() === TypeMap::KIND_NON_NULL; }); @@ -64,7 +67,7 @@ public function assertValidArguments(FieldInterface $field, AstFieldInterface $q throw new ResolveException(sprintf('Unknown argument "%s" on field "%s"', $astArgument->getName(), $field->getName()), $astArgument->getLocation()); } - $argument = $field->getArgument($astArgument->getName()); + $argument = $field->getArgument($astArgument->getName()); $argumentType = $argument->getType()->getNullableType(); switch ($argumentType->getKind()) { @@ -88,12 +91,15 @@ public function assertValidArguments(FieldInterface $field, AstFieldInterface $q } } - if (count($requiredArguments)) { + if ($requiredArguments !== []) { throw new ResolveException(sprintf('Require "%s" arguments to query "%s"', implode(', ', array_keys($requiredArguments)), $query->getName())); } } - public function assertValidResolvedValueForField(FieldInterface $field, $resolvedValue) + /** + * @throws ResolveException + */ + public function assertValidResolvedValueForField(FieldInterface $field, $resolvedValue): void { if (null === $resolvedValue && $field->getType()->getKind() === TypeMap::KIND_NON_NULL) { throw new ResolveException(sprintf('Cannot return null for non-nullable field "%s"', $field->getName())); @@ -107,7 +113,10 @@ public function assertValidResolvedValueForField(FieldInterface $field, $resolve } } - public function assertTypeImplementsInterface(AbstractType $type, AbstractInterfaceType $interface) + /** + * @throws ResolveException + */ + public function assertTypeImplementsInterface(AbstractType $type, AbstractInterfaceType $interface): void { if ($type instanceof AbstractObjectType) { foreach ($type->getInterfaces() as $typeInterface) { @@ -120,7 +129,10 @@ public function assertTypeImplementsInterface(AbstractType $type, AbstractInterf throw new ResolveException(sprintf('Type "%s" does not implement "%s"', $type->getName(), $interface->getName())); } - public function assertTypeInUnionTypes(AbstractType $type, AbstractUnionType $unionType) + /** + * @throws ResolveException + */ + public function assertTypeInUnionTypes(AbstractType $type, AbstractUnionType $unionType): void { foreach ($unionType->getTypes() as $unionTypeItem) { if ($unionTypeItem->getName() === $type->getName()) { diff --git a/src/Validator/SchemaValidator/SchemaValidator.php b/src/Validator/SchemaValidator/SchemaValidator.php index 78365e22..0b334c5a 100644 --- a/src/Validator/SchemaValidator/SchemaValidator.php +++ b/src/Validator/SchemaValidator/SchemaValidator.php @@ -18,23 +18,19 @@ class SchemaValidator { - /** @var ConfigValidator */ - private $configValidator = null; /** - * @param AbstractSchema $schema - * * @throws ConfigurationException */ - public function validate(AbstractSchema $schema) + public function validate(AbstractSchema $schema): void { if (!$schema->getQueryType()->hasFields()) { throw new ConfigurationException('Schema has to have fields'); } - $this->configValidator = ConfigValidator::getInstance(); + $configValidator = ConfigValidator::getInstance(); foreach ($schema->getQueryType()->getConfig()->getFields() as $field) { - $this->configValidator->assertValidConfig($field->getConfig()); + $configValidator->assertValidConfig($field->getConfig()); if ($field->getType() instanceof AbstractObjectType) { $this->assertInterfaceImplementationCorrect($field->getType()); @@ -43,11 +39,9 @@ public function validate(AbstractSchema $schema) } /** - * @param AbstractObjectType $type - * * @throws ConfigurationException */ - protected function assertInterfaceImplementationCorrect(AbstractObjectType $type) + protected function assertInterfaceImplementationCorrect(AbstractObjectType $type): void { if (!$type->getInterfaces()) { return; @@ -61,18 +55,18 @@ protected function assertInterfaceImplementationCorrect(AbstractObjectType $type } /** - * @param Field $intField - * @param Field $objField - * @param AbstractInterfaceType $interface + * @param Field $intField + * @param Field $objField * * @throws ConfigurationException */ - protected function assertFieldsIdentical($intField, $objField, AbstractInterfaceType $interface) + protected function assertFieldsIdentical($intField, $objField, AbstractInterfaceType $interface): void { $isValid = true; if ($intField->getType()->isCompositeType() !== $objField->getType()->isCompositeType()) { $isValid = false; } + if ($intField->getType()->getNamedType()->getName() != $objField->getType()->getNamedType()->getName()) { $isValid = false; } diff --git a/tests/DataProvider/TestConfig.php b/tests/DataProvider/TestConfig.php index 802baae6..2a669dcb 100644 --- a/tests/DataProvider/TestConfig.php +++ b/tests/DataProvider/TestConfig.php @@ -14,7 +14,7 @@ class TestConfig extends AbstractConfig { - public function getRules() + public function getRules(): array { return [ 'name' => ['type' => TypeService::TYPE_ANY, 'required' => true], diff --git a/tests/DataProvider/TestConfigExtraFields.php b/tests/DataProvider/TestConfigExtraFields.php index f8aa17e6..9f28992a 100644 --- a/tests/DataProvider/TestConfigExtraFields.php +++ b/tests/DataProvider/TestConfigExtraFields.php @@ -17,7 +17,7 @@ class TestConfigExtraFields extends AbstractConfig protected $extraFieldsAllowed = true; - public function getRules() + public function getRules(): array { return [ 'name' => ['type' => TypeService::TYPE_ANY, 'required' => true] diff --git a/tests/DataProvider/TestConfigInvalidRule.php b/tests/DataProvider/TestConfigInvalidRule.php index 0a61ab85..e7e31bb7 100644 --- a/tests/DataProvider/TestConfigInvalidRule.php +++ b/tests/DataProvider/TestConfigInvalidRule.php @@ -8,7 +8,7 @@ class TestConfigInvalidRule extends AbstractConfig { - public function getRules() + public function getRules(): array { return [ 'name' => ['type' => TypeService::TYPE_ANY, 'required' => true], diff --git a/tests/DataProvider/TestEmptySchema.php b/tests/DataProvider/TestEmptySchema.php index 004bc45e..b3d3b060 100644 --- a/tests/DataProvider/TestEmptySchema.php +++ b/tests/DataProvider/TestEmptySchema.php @@ -14,12 +14,12 @@ class TestEmptySchema extends AbstractSchema { - public function build(SchemaConfig $config) + public function build(SchemaConfig $config): void { } - public function getName($config) + public function getName($config): string { return 'TestSchema'; } diff --git a/tests/DataProvider/TestEnumType.php b/tests/DataProvider/TestEnumType.php index 90a1b8d8..fdc60f2a 100644 --- a/tests/DataProvider/TestEnumType.php +++ b/tests/DataProvider/TestEnumType.php @@ -13,7 +13,7 @@ class TestEnumType extends AbstractEnumType { - public function getValues() + public function getValues(): array { return [ [ diff --git a/tests/DataProvider/TestExtendedType.php b/tests/DataProvider/TestExtendedType.php index 4acc4252..2d1ea185 100644 --- a/tests/DataProvider/TestExtendedType.php +++ b/tests/DataProvider/TestExtendedType.php @@ -15,7 +15,7 @@ class TestExtendedType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config->applyInterface(new TestInterfaceType()) ->addField('ownField', new StringType()); diff --git a/tests/DataProvider/TestField.php b/tests/DataProvider/TestField.php index b1764754..53c94d2f 100644 --- a/tests/DataProvider/TestField.php +++ b/tests/DataProvider/TestField.php @@ -18,7 +18,7 @@ class TestField extends AbstractField /** * @return AbstractObjectType */ - public function getType() + public function getType(): \Youshido\GraphQL\Type\Scalar\IntType { return new IntType(); } @@ -28,7 +28,7 @@ public function resolve($value, array $args, ResolveInfo $info) return $value; } - public function getDescription() + public function getDescription(): string { return 'description'; } diff --git a/tests/DataProvider/TestInputField.php b/tests/DataProvider/TestInputField.php index 2340e560..20b165ed 100644 --- a/tests/DataProvider/TestInputField.php +++ b/tests/DataProvider/TestInputField.php @@ -18,17 +18,17 @@ class TestInputField extends AbstractInputField /** * @return InputTypeInterface */ - public function getType() + public function getType(): \Youshido\GraphQL\Type\Scalar\IntType { return new IntType(); } - public function getDescription() + public function getDescription(): string { return 'description'; } - public function getDefaultValue() + public function getDefaultValue(): string { return 'default'; } diff --git a/tests/DataProvider/TestInputObjectType.php b/tests/DataProvider/TestInputObjectType.php index 95d34b0a..fcbb063c 100644 --- a/tests/DataProvider/TestInputObjectType.php +++ b/tests/DataProvider/TestInputObjectType.php @@ -15,7 +15,7 @@ class TestInputObjectType extends AbstractInputObjectType { - public function build($config) + public function build($config): void { $config->addField('name', new NonNullType(new StringType())); } diff --git a/tests/DataProvider/TestInterfaceType.php b/tests/DataProvider/TestInterfaceType.php index 68a562ad..489914d3 100644 --- a/tests/DataProvider/TestInterfaceType.php +++ b/tests/DataProvider/TestInterfaceType.php @@ -9,18 +9,19 @@ namespace Youshido\Tests\DataProvider; +use Youshido\GraphQL\Config\Object\InterfaceTypeConfig; use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType; use Youshido\GraphQL\Type\Scalar\StringType; class TestInterfaceType extends AbstractInterfaceType { - public function resolveType($object) + public function resolveType($object): object { return is_object($object) ? $object : new TestObjectType(); } - public function build($config) + public function build(InterfaceTypeConfig $config): void { $config->addField('name', new StringType()); } diff --git a/tests/DataProvider/TestListType.php b/tests/DataProvider/TestListType.php index 87f779c4..22c9bee3 100644 --- a/tests/DataProvider/TestListType.php +++ b/tests/DataProvider/TestListType.php @@ -14,7 +14,7 @@ class TestListType extends AbstractListType { - public function getItemType() + public function getItemType(): \Youshido\GraphQL\Type\Scalar\StringType { return new StringType(); } diff --git a/tests/DataProvider/TestMutationObjectType.php b/tests/DataProvider/TestMutationObjectType.php index c0747499..62a03a47 100644 --- a/tests/DataProvider/TestMutationObjectType.php +++ b/tests/DataProvider/TestMutationObjectType.php @@ -9,18 +9,19 @@ namespace Youshido\Tests\DataProvider; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\Object\AbstractMutationObjectType; use Youshido\GraphQL\Type\Scalar\IntType; use Youshido\GraphQL\Type\Scalar\StringType; class TestMutationObjectType extends AbstractMutationObjectType { - public function getOutputType() + public function getOutputType(): \Youshido\GraphQL\Type\Scalar\StringType { return new StringType(); } - public function build($config) + public function build(ObjectTypeConfig $config): void { $this->addArgument('increment', new IntType()); } diff --git a/tests/DataProvider/TestObjectType.php b/tests/DataProvider/TestObjectType.php index f0e43a8b..638a0909 100644 --- a/tests/DataProvider/TestObjectType.php +++ b/tests/DataProvider/TestObjectType.php @@ -8,6 +8,7 @@ namespace Youshido\Tests\DataProvider; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Object\ObjectType; use Youshido\GraphQL\Type\Scalar\IntType; @@ -17,7 +18,7 @@ class TestObjectType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config ->addField('id', new IntType()) @@ -41,8 +42,8 @@ public function build($config) 'args' => [ 'noop' => new IntType() ], - 'resolve' => function ($value, $args, $info) { - return ['address' => '1234 Street']; + 'resolve' => static function ($value, $args, $info) : array { + return ['address' => '1234 Street']; } ] ) @@ -52,19 +53,19 @@ public function build($config) 'args' => [ 'value' => new NonNullType(new StringType()) ], - 'resolve' => function ($value, $args, $info) { + 'resolve' => static function ($value, array $args, $info) { return $args['value']; } ] ); } - public function getInterfaces() + public function getInterfaces(): array { return [new TestInterfaceType()]; } - public function getData() + public function getData(): array { return [ 'id' => 1, diff --git a/tests/DataProvider/TestResolveInfo.php b/tests/DataProvider/TestResolveInfo.php index 2bf68c1c..6589f9d2 100644 --- a/tests/DataProvider/TestResolveInfo.php +++ b/tests/DataProvider/TestResolveInfo.php @@ -14,7 +14,7 @@ class TestResolveInfo { - public static function createTestResolveInfo($field = null) + public static function createTestResolveInfo($field = null): \Youshido\GraphQL\Execution\ResolveInfo { if (empty($field)) { $field = new TestField(); diff --git a/tests/DataProvider/TestScalarDataProvider.php b/tests/DataProvider/TestScalarDataProvider.php index b49a0771..5056e545 100644 --- a/tests/DataProvider/TestScalarDataProvider.php +++ b/tests/DataProvider/TestScalarDataProvider.php @@ -12,7 +12,7 @@ class TestScalarDataProvider { - public static function getsList() + public static function getsList(): array { return [ "Int", @@ -23,7 +23,7 @@ public static function getsList() ]; } - public static function getIntTestData() + public static function getIntTestData(): array { /** input, serialization, isValid */ return [ @@ -47,7 +47,7 @@ public static function getIntTestData() ]; } - public static function getFloatTestData() + public static function getFloatTestData(): array { return [ [1, 1.0, true], @@ -63,7 +63,7 @@ public static function getFloatTestData() ]; } - public static function getStringTestData() + public static function getStringTestData(): array { return [ ["string", "string", true], @@ -76,7 +76,7 @@ public static function getStringTestData() ]; } - public static function getBooleanTestData() + public static function getBooleanTestData(): array { return [ ["string", true, false], @@ -92,7 +92,7 @@ public static function getBooleanTestData() ]; } - public static function getIdTestData() + public static function getIdTestData(): array { return [ ["string-id", "string-id", true], @@ -101,7 +101,7 @@ public static function getIdTestData() ]; } - public static function getDatetimeTestData() + public static function getDatetimeTestData(): array { $time = time(); return [ @@ -110,7 +110,7 @@ public static function getDatetimeTestData() ]; } - public static function getDatetimetzTestData() + public static function getDatetimetzTestData(): array { $time = time(); return [ @@ -119,7 +119,7 @@ public static function getDatetimetzTestData() ]; } - public static function getDateTestData() + public static function getDateTestData(): array { $time = time(); return [ @@ -129,7 +129,7 @@ public static function getDateTestData() } - public static function getTimestampTestData() + public static function getTimestampTestData(): array { $time = time(); return [ diff --git a/tests/DataProvider/TestSchema.php b/tests/DataProvider/TestSchema.php index 26726d83..d3a32729 100644 --- a/tests/DataProvider/TestSchema.php +++ b/tests/DataProvider/TestSchema.php @@ -17,14 +17,14 @@ class TestSchema extends AbstractSchema { - private $testStatusValue = 0; + private int $testStatusValue = 0; - public function build(SchemaConfig $config) + public function build(SchemaConfig $config): void { $config->getQuery()->addFields([ 'me' => [ 'type' => new TestObjectType(), - 'resolve' => function ($value, $args, ResolveInfo $info) { + 'resolve' => static function ($value, $args, ResolveInfo $info) { return $info->getReturnType()->getData(); } ], diff --git a/tests/DataProvider/TestTimeType.php b/tests/DataProvider/TestTimeType.php index 3d9f285b..fc59877b 100644 --- a/tests/DataProvider/TestTimeType.php +++ b/tests/DataProvider/TestTimeType.php @@ -9,41 +9,42 @@ namespace Youshido\Tests\DataProvider; +use DateTime; use Youshido\GraphQL\Type\Scalar\AbstractScalarType; class TestTimeType extends AbstractScalarType { - public function getName() + public function getName(): string { return 'TestTime'; } /** - * @param $value \DateTime - * @return null|string + * @param $value DateTime + * @return string|DateTime|null */ - public function serialize($value) + public function serialize($value): string|null|DateTime { if ($value === null) { return null; } - return $value instanceof \DateTime ? $value->format('H:i:s') : $value; + return $value instanceof DateTime ? $value->format('H:i:s') : $value; } - public function isValidValue($value) + public function isValidValue(mixed $value): bool { if (is_object($value)) { return true; } - $d = \DateTime::createFromFormat('H:i:s', $value); + $d = DateTime::createFromFormat('H:i:s', $value); return $d && $d->format('H:i:s') == $value; } - public function getDescription() + public function getDescription(): string { return 'Representation time in "H:i:s" format'; } diff --git a/tests/DataProvider/TestUnionType.php b/tests/DataProvider/TestUnionType.php index 96e1dd9c..8738ea1f 100644 --- a/tests/DataProvider/TestUnionType.php +++ b/tests/DataProvider/TestUnionType.php @@ -13,19 +13,19 @@ class TestUnionType extends AbstractUnionType { - public function getTypes() + public function getTypes(): array { return [ new TestObjectType() ]; } - public function resolveType($object) + public function resolveType(object $object) { return $object; } - public function getDescription() + public function getDescription(): string { return 'Union collect cars types'; } diff --git a/tests/Issues/Issue109/Issue109Schema.php b/tests/Issues/Issue109/Issue109Schema.php index 8ba4ab8f..6535e13f 100644 --- a/tests/Issues/Issue109/Issue109Schema.php +++ b/tests/Issues/Issue109/Issue109Schema.php @@ -11,7 +11,7 @@ class Issue109Schema extends AbstractSchema { - public function build(SchemaConfig $config) + public function build(SchemaConfig $config): void { $config->setQuery( new ObjectType([ @@ -40,14 +40,13 @@ public function build(SchemaConfig $config) ] ] ]), - 'resolve' => function ($source, array $args, ResolveInfo $info) { + 'resolve' => static function ($source, array $args, ResolveInfo $info) : array { $internalArgs = [ 'comment_id' => 200 ]; if ($field = $info->getFieldAST('comments')->hasArguments()) { $internalArgs['comment_id'] = $info->getFieldAST('comments')->getArgumentValue('comment_id'); } - return [ "id" => 1, "title" => "New approach in API has been revealed", diff --git a/tests/Issues/Issue109/Issue109Test.php b/tests/Issues/Issue109/Issue109Test.php index 0e6a9628..fe24765d 100644 --- a/tests/Issues/Issue109/Issue109Test.php +++ b/tests/Issues/Issue109/Issue109Test.php @@ -7,7 +7,7 @@ class Issue109Test extends \PHPUnit_Framework_TestCase { - public function testInternalVariableArgument() + public function testInternalVariableArgument(): void { $schema = new Issue109Schema(); $processor = new Processor($schema); diff --git a/tests/Issues/Issue116/Issue116Test.php b/tests/Issues/Issue116/Issue116Test.php index 3ad2ce71..4e31c0f9 100644 --- a/tests/Issues/Issue116/Issue116Test.php +++ b/tests/Issues/Issue116/Issue116Test.php @@ -13,7 +13,7 @@ class Issue116Test extends \PHPUnit_Framework_TestCase { - public function testInternalVariableArgument() + public function testInternalVariableArgument(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -32,12 +32,11 @@ public function testInternalVariableArgument() 'args' => [ 'size' => new NonNullType(new IntType()), ], - 'resolve' => function ($source, $args) { + 'resolve' => static function ($source, array $args) : array { $res = []; foreach (range(1, $args['size']) as $i) { $res[] = 'Cursor #' . $i; } - return $res; } ], @@ -48,7 +47,7 @@ public function testInternalVariableArgument() 'args' => [ 'first' => new IntType(), ], - 'resolve' => function () { + 'resolve' => static function () : array { return [ 'pageInfo' => [ 'totalEdges' => 10, diff --git a/tests/Issues/Issue131/Issue131Test.php b/tests/Issues/Issue131/Issue131Test.php index 1372dca1..2ac73fc4 100644 --- a/tests/Issues/Issue131/Issue131Test.php +++ b/tests/Issues/Issue131/Issue131Test.php @@ -15,7 +15,7 @@ class Issue131Test extends \PHPUnit_Framework_TestCase { - public function testInternalVariableArgument() + public function testInternalVariableArgument(): void { @@ -47,7 +47,7 @@ public function testInternalVariableArgument() ] ])) ], - 'resolve' => function ($source, $args) { + 'resolve' => static function ($source, array $args) : array { return [ 'id' => '1', 'name' => sprintf('Meeting with %d beans', count($args['related_beans'])), diff --git a/tests/Issues/Issue149/Issue149Test.php b/tests/Issues/Issue149/Issue149Test.php index f42df1dc..956d3c16 100644 --- a/tests/Issues/Issue149/Issue149Test.php +++ b/tests/Issues/Issue149/Issue149Test.php @@ -13,7 +13,7 @@ class Issue149Test extends \PHPUnit_Framework_TestCase { - public function testInternalVariableArgument() + public function testInternalVariableArgument(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -36,7 +36,7 @@ public function testInternalVariableArgument() ])), ], ]), - 'resolve' => function () { + 'resolve' => static function () : array { return [ 'id' => 1, 'name' => 'John', diff --git a/tests/Issues/Issue151/Issue151Test.php b/tests/Issues/Issue151/Issue151Test.php index b3f58900..b1607637 100644 --- a/tests/Issues/Issue151/Issue151Test.php +++ b/tests/Issues/Issue151/Issue151Test.php @@ -12,7 +12,7 @@ class Issue151Test extends \PHPUnit_Framework_TestCase { - public function testInternalVariableArgument() + public function testInternalVariableArgument(): void { $type1 = new ObjectType([ 'name' => 'Type1', @@ -32,11 +32,10 @@ public function testInternalVariableArgument() $unionType = new UnionType([ 'name' => 'Union', 'types' => [$type1, $type2], - 'resolveType' => function ($value) use ($type1, $type2) { + 'resolveType' => static function (array $value) use ($type1, $type2) { if (isset($value['name'])) { return $type1; } - return $type2; }, ]); @@ -47,7 +46,7 @@ public function testInternalVariableArgument() 'fields' => [ 'list' => [ 'type' => new ListType($unionType), - 'resolve' => function () { + 'resolve' => static function () : array { return [ [ 'id' => 1, @@ -64,7 +63,7 @@ public function testInternalVariableArgument() ]), ]); $processor = new Processor($schema); - $response = $processor->processPayload(' + $processor->processPayload(' { list { ...UnitFragment diff --git a/tests/Issues/Issue171/Issue171Schema.php b/tests/Issues/Issue171/Issue171Schema.php index 95110c24..d6a597b3 100644 --- a/tests/Issues/Issue171/Issue171Schema.php +++ b/tests/Issues/Issue171/Issue171Schema.php @@ -1,6 +1,7 @@ getQuery()->addField( 'plan', @@ -21,7 +22,7 @@ public function build(SchemaConfig $config) class PlanType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config->addField('kpi_status', [ 'type' => new KpiStatusType(), @@ -31,7 +32,7 @@ public function build($config) class KpiStatusType extends AbstractEnumType { - public function getValues() + public function getValues(): array { return [ [ diff --git a/tests/Issues/Issue171/Issue171Test.php b/tests/Issues/Issue171/Issue171Test.php index f4163bc6..12d1ff2e 100644 --- a/tests/Issues/Issue171/Issue171Test.php +++ b/tests/Issues/Issue171/Issue171Test.php @@ -5,15 +5,16 @@ class Issue171Test extends \PHPUnit_Framework_TestCase { - public function testItSetsDeprecationReasonToNullByDefault() + public function testItSetsDeprecationReasonToNullByDefault(): void { $schema = new Issue171Schema(); $processor = new Processor($schema); $processor->processPayload($this->getIntrospectionQuery(), []); + $resp = $processor->getResponseData(); - $enumTypes = array_filter($resp['data']['__schema']['types'], function($type){ + $enumTypes = array_filter($resp['data']['__schema']['types'], static function (array $type) : bool { return ($type['kind'] === 'ENUM'); }); diff --git a/tests/Issues/Issue193/Issue193Test.php b/tests/Issues/Issue193/Issue193Test.php index 80d673f0..a9565815 100644 --- a/tests/Issues/Issue193/Issue193Test.php +++ b/tests/Issues/Issue193/Issue193Test.php @@ -2,6 +2,8 @@ namespace Youshido\Tests\Issues\Issue193; +use Youshido\GraphQL\Config\Object\InterfaceTypeConfig; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Config\Schema\SchemaConfig; use Youshido\GraphQL\Execution\Processor; use Youshido\GraphQL\Schema\AbstractSchema; @@ -13,15 +15,16 @@ class Issue193Test extends \PHPUnit_Framework_TestCase { - public function testResolvedInterfacesShouldBeRegistered() + public function testResolvedInterfacesShouldBeRegistered(): void { $schema = new Issue193Schema(); $processor = new Processor($schema); $processor->processPayload($this->getIntrospectionQuery(), []); + $resp = $processor->getResponseData(); - $typeNames = array_map(function ($type) { + $typeNames = array_map(static function (array $type) { return $type['name']; }, $resp['data']['__schema']['types']); @@ -67,7 +70,7 @@ private function getIntrospectionQuery() class Issue193Schema extends AbstractSchema { - public function build(SchemaConfig $config) + public function build(SchemaConfig $config): void { $config->getQuery()->addField( 'post', @@ -81,7 +84,7 @@ public function build(SchemaConfig $config) class PostType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config->applyInterface(new ContentBlockInterface()); $config->addFields([ @@ -89,7 +92,7 @@ public function build($config) ]); } - public function getInterfaces() + public function getInterfaces(): array { return [new ContentBlockInterface()]; } @@ -97,7 +100,7 @@ public function getInterfaces() class UndiscoveredType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config->applyInterface(new ContentBlockInterface()); } @@ -105,13 +108,13 @@ public function build($config) class ContentBlockInterface extends AbstractInterfaceType { - public function build($config) + public function build(InterfaceTypeConfig $config): void { $config->addField('title', new NonNullType(new StringType())); $config->addField('summary', new StringType()); } - public function resolveType($object) + public function resolveType($object): \Youshido\Tests\Issues\Issue193\PostType|\Youshido\Tests\Issues\Issue193\UndiscoveredType { if (isset($object['title'])) { return new PostType(); @@ -120,7 +123,7 @@ public function resolveType($object) return new UndiscoveredType(); } - public function getImplementations() + public function getImplementations(): array { return [ new PostType(), diff --git a/tests/Issues/Issue194/ProcessorTest.php b/tests/Issues/Issue194/ProcessorTest.php index 78a147cb..6d9b8d4b 100644 --- a/tests/Issues/Issue194/ProcessorTest.php +++ b/tests/Issues/Issue194/ProcessorTest.php @@ -13,7 +13,7 @@ class ProcessorTest extends TestCase { - public function testNonNullDefaultValue() + public function testNonNullDefaultValue(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -27,7 +27,7 @@ public function testNonNullDefaultValue() 'defaultValue' => 20, ], ], - 'resolve' => static function ($source, $args, ResolveInfo $info) { + 'resolve' => static function ($source, array $args, ResolveInfo $info): string { return 'Alex age ' . $args['age']; }, ], @@ -44,7 +44,7 @@ public function testNonNullDefaultValue() $processor->processPayload('{ currentUser(age:10) }')->getResponseData()); } - public function testNullDefaultValue() + public function testNullDefaultValue(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -58,7 +58,7 @@ public function testNullDefaultValue() 'defaultValue' => null, ], ], - 'resolve' => static function ($source, $args, ResolveInfo $info) { + 'resolve' => static function ($source, array $args, ResolveInfo $info): string { if ($args['age'] === null) { $args['age'] = 25; } diff --git a/tests/Issues/Issue201/Issue201Test.php b/tests/Issues/Issue201/Issue201Test.php index b7810489..b2cf8acb 100644 --- a/tests/Issues/Issue201/Issue201Test.php +++ b/tests/Issues/Issue201/Issue201Test.php @@ -16,7 +16,7 @@ class Issue201Test extends TestCase * @expectedException \Youshido\GraphQL\Exception\ConfigurationException * @expectedExceptionMessage Type "user" was defined more than once */ - public function testExceptionOnDuplicateTypeName() + public function testExceptionOnDuplicateTypeName(): void { $schema = new Schema([ 'query' => new ObjectType([ diff --git a/tests/Issues/Issue210/TypeServiceTest.php b/tests/Issues/Issue210/TypeServiceTest.php index deca066d..200f4ef8 100644 --- a/tests/Issues/Issue210/TypeServiceTest.php +++ b/tests/Issues/Issue210/TypeServiceTest.php @@ -8,7 +8,7 @@ class TypeServiceTest extends TestCase { - public function testGetPropertyValue() + public function testGetPropertyValue(): void { $object = new DummyObjectWithTrickyGetters(); @@ -20,17 +20,17 @@ public function testGetPropertyValue() class DummyObjectWithTrickyGetters { - public function getIssuer() + public function getIssuer(): string { return 'Foo'; } - public function something() + public function something(): string { return 'something'; } - public function issuerName() + public function issuerName(): string { return 'Bar'; } diff --git a/tests/Issues/Issue220/ResolvableObjectTraitTest.php b/tests/Issues/Issue220/ResolvableObjectTraitTest.php index ae96b69c..10908a43 100644 --- a/tests/Issues/Issue220/ResolvableObjectTraitTest.php +++ b/tests/Issues/Issue220/ResolvableObjectTraitTest.php @@ -3,6 +3,7 @@ namespace Youshido\Tests\Issues\Issue220; use PHPUnit\Framework\TestCase; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Field\Field; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Scalar\StringType; @@ -11,7 +12,7 @@ class Issue220Test extends TestCase { - public function testValueNotFoundInResolveScalarType() + public function testValueNotFoundInResolveScalarType(): void { $fieldWithResolve = new Field([ 'name' => 'scalarField', @@ -23,7 +24,7 @@ public function testValueNotFoundInResolveScalarType() $this->assertEquals(null, $fieldWithResolve->resolve([], [], $resolveInfo)); } - public function testValueNotFoundInResolveObjectType() + public function testValueNotFoundInResolveObjectType(): void { $fieldWithResolve = new Field([ 'name' => 'scalarField', @@ -35,7 +36,7 @@ public function testValueNotFoundInResolveObjectType() $this->assertEquals(null, $fieldWithResolve->resolve([], [], $resolveInfo)); } - public function testValueFoundInResolve() + public function testValueFoundInResolve(): void { $fieldWithResolve = new Field([ 'name' => 'scalarField', @@ -50,7 +51,7 @@ public function testValueFoundInResolve() class ArticleType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config->addFields([ 'title' => new StringType(), diff --git a/tests/Issues/Issue90/Issue90Schema.php b/tests/Issues/Issue90/Issue90Schema.php index 03f0d28a..ef77ddfe 100644 --- a/tests/Issues/Issue90/Issue90Schema.php +++ b/tests/Issues/Issue90/Issue90Schema.php @@ -9,7 +9,7 @@ class Issue90Schema extends AbstractSchema { - public function build(SchemaConfig $config) + public function build(SchemaConfig $config): void { $config->setQuery( new ObjectType([ @@ -20,12 +20,10 @@ public function build(SchemaConfig $config) 'args' => [ 'date' => new DateTimeType('Y-m-d H:ia') ], - 'resolve' => function ($value, $args, $info) { - + 'resolve' => static function ($value, array $args, $info) { if (isset($args['date'])) { return $args['date']; } - return null; } ] @@ -42,12 +40,10 @@ public function build(SchemaConfig $config) 'args' => [ 'date' => new DateTimeType('Y-m-d H:ia') ], - 'resolve' => function ($value, $args, $info) { - + 'resolve' => static function ($value, array $args, $info) { if (isset($args['date'])) { return $args['date']; } - return null; } ] diff --git a/tests/Issues/Issue90/Issue90Test.php b/tests/Issues/Issue90/Issue90Test.php index e30b2729..20720a6c 100644 --- a/tests/Issues/Issue90/Issue90Test.php +++ b/tests/Issues/Issue90/Issue90Test.php @@ -13,11 +13,12 @@ class Issue90Test extends \PHPUnit_Framework_TestCase { - public function testQueryDateTimeTypeWithDateParameter() + public function testQueryDateTimeTypeWithDateParameter(): void { $schema = new Issue90Schema(); $processor = new Processor($schema); - $processor->processPayload("query{ echo(date: \"2016-11-25 09:53am\") }"); + $processor->processPayload('query{ echo(date: "2016-11-25 09:53am") }'); + $res = $processor->getResponseData(); self::assertCount(1, $res, "Invalid response array received"); //only data expected @@ -27,10 +28,11 @@ public function testQueryDateTimeTypeWithDateParameter() self::assertEquals("2016-11-25 09:53am", $res['data']['echo']); } - public function testQueryDateTimeTypeWithoutParameter() + public function testQueryDateTimeTypeWithoutParameter(): void { $processor = new Processor(new Issue90Schema()); $processor->processPayload("query{ echo }"); + $res = $processor->getResponseData(); self::assertCount(1, $res, "Invalid response array received"); //only data expected @@ -38,10 +40,11 @@ public function testQueryDateTimeTypeWithoutParameter() self::assertNull($res['data']['echo']); } - public function testQueryDateTimeTypeWithNullParameter() + public function testQueryDateTimeTypeWithNullParameter(): void { $processor = new Processor(new Issue90Schema()); $processor->processPayload("query{ echo(date: null) }"); + $res = $processor->getResponseData(); self::assertCount(1, $res, "Invalid response array received"); //only data expected @@ -49,11 +52,12 @@ public function testQueryDateTimeTypeWithNullParameter() self::assertNull($res['data']['echo'], "Error Quering with explicit date null parameter "); } - public function testMutatingDateTimeWithParameter() + public function testMutatingDateTimeWithParameter(): void { $schema = new Issue90Schema(); $processor = new Processor($schema); - $processor->processPayload("mutation{ echo(date: \"2016-11-25 09:53am\") }"); + $processor->processPayload('mutation{ echo(date: "2016-11-25 09:53am") }'); + $res = $processor->getResponseData(); self::assertCount(1, $res, "Invalid response array received"); //only data expected @@ -63,11 +67,12 @@ public function testMutatingDateTimeWithParameter() self::assertEquals("2016-11-25 09:53am", $res['data']['echo']); } - public function testMutatingDateTimeWithExplicitNullParameter() + public function testMutatingDateTimeWithExplicitNullParameter(): void { $schema = new Issue90Schema(); $processor = new Processor($schema); $processor->processPayload("mutation{ echo(date: null) }"); + $res = $processor->getResponseData(); self::assertCount(1, $res, "Invalid response array received"); //only data expected diff --git a/tests/Issues/Issue98/TypeServiceTest.php b/tests/Issues/Issue98/TypeServiceTest.php index c137dea5..065d3cb5 100644 --- a/tests/Issues/Issue98/TypeServiceTest.php +++ b/tests/Issues/Issue98/TypeServiceTest.php @@ -7,7 +7,7 @@ class TypeServiceTest extends TestCase { - public function testPropertGetValueWithMagicGet() + public function testPropertGetValueWithMagicGet(): void { $object = new DummyObjectWithMagicGet(); @@ -15,7 +15,7 @@ public function testPropertGetValueWithMagicGet() $this->assertEquals('getbar', TypeService::getPropertyValue($object, 'anything')); } - public function testPropertyGetValueWithMagicCall() + public function testPropertyGetValueWithMagicCall(): void { $object = new DummyObjectWithMagicCall(); diff --git a/tests/Issues/Issue99/Issue99Schema.php b/tests/Issues/Issue99/Issue99Schema.php index 8ac032df..5620db80 100644 --- a/tests/Issues/Issue99/Issue99Schema.php +++ b/tests/Issues/Issue99/Issue99Schema.php @@ -13,7 +13,7 @@ class Issue99Schema extends AbstractSchema { - public function build(SchemaConfig $config) + public function build(SchemaConfig $config): void { $config->setQuery( new ObjectType([ @@ -39,9 +39,8 @@ public function build(SchemaConfig $config) ])) ] ], - 'resolve' => function($source, $args) { + 'resolve' => static function ($source, array $args) : array { $x = isset($args['argX']['x']) ? $args['argX']['x'] : Issue99Test::BUG_EXISTS_VALUE; - return [ 'value' => $x ]; @@ -52,7 +51,7 @@ public function build(SchemaConfig $config) 'args' => [ 'example' => new StringType() ], - 'resolve' => function () { + 'resolve' => static function () : array { return [ ['id' => 1], ['id' => 2], diff --git a/tests/Issues/Issue99/Issue99Test.php b/tests/Issues/Issue99/Issue99Test.php index ae6ebf5a..59df05e9 100644 --- a/tests/Issues/Issue99/Issue99Test.php +++ b/tests/Issues/Issue99/Issue99Test.php @@ -10,14 +10,16 @@ */ class Issue99Test extends \PHPUnit_Framework_TestCase { - const BUG_NOT_EXISTS_VALUE = 'bug not exists'; - const BUG_EXISTS_VALUE = 'bug exists'; + final const BUG_NOT_EXISTS_VALUE = 'bug not exists'; + + final const BUG_EXISTS_VALUE = 'bug exists'; - public function testQueryDateTimeTypeWithDateParameter() + public function testQueryDateTimeTypeWithDateParameter(): void { $schema = new Issue99Schema(); $processor = new Processor($schema); - $processor->processPayload(sprintf("{ items{id, custom(argX: {x: \"%s\"}){ value } } }", self::BUG_NOT_EXISTS_VALUE)); + $processor->processPayload(sprintf('{ items{id, custom(argX: {x: "%s"}){ value } } }', self::BUG_NOT_EXISTS_VALUE)); + $res = $processor->getResponseData(); self::assertTrue(isset($res['data']['items'])); diff --git a/tests/Library/Config/ConfigTest.php b/tests/Library/Config/ConfigTest.php index 1fba5740..7607f9a4 100644 --- a/tests/Library/Config/ConfigTest.php +++ b/tests/Library/Config/ConfigTest.php @@ -24,7 +24,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testEmptyParams() + public function testEmptyParams(): void { new TestConfig([]); } @@ -32,7 +32,7 @@ public function testEmptyParams() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidParams() + public function testInvalidParams(): void { ConfigValidator::getInstance()->assertValidConfig(new TestConfig(['id' => 1])); } @@ -40,13 +40,13 @@ public function testInvalidParams() /** * @expectedException \Exception */ - public function testInvalidMethod() + public function testInvalidMethod(): void { $config = new TestConfig(['name' => 'test']); $config->doSomethingStrange(); } - public function testMethods() + public function testMethods(): void { $name = 'Test'; $rules = [ @@ -80,7 +80,9 @@ public function testMethods() ] ]); - $finalConfig = new TestConfig(['name' => $name . 'final', 'resolve' => function () { return []; }], $object, true); + $finalConfig = new TestConfig(['name' => $name . 'final', 'resolve' => static function () : array { + return []; + }], $object, true); $this->assertEquals($finalConfig->getType(), null); $rules['resolve']['required'] = true; @@ -98,15 +100,15 @@ public function testMethods() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testFinalRule() + public function testFinalRule(): void { - ConfigValidator::getInstance()->assertValidConfig(new TestConfig(['name' => 'Test' . 'final'], null, true)); + ConfigValidator::getInstance()->assertValidConfig(new TestConfig(['name' => 'Testfinal'], null, true)); } /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidRule() + public function testInvalidRule(): void { ConfigValidator::getInstance()->assertValidConfig( new TestConfigInvalidRule(['name' => 'Test', 'invalidRuleField' => 'test'], null, null) @@ -116,7 +118,7 @@ public function testInvalidRule() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testEnumConfig() + public function testEnumConfig(): void { $enumType = new EnumType([ 'name' => 'Status', diff --git a/tests/Library/Config/FieldConfigTest.php b/tests/Library/Config/FieldConfigTest.php index 4d14b8fd..bf860282 100644 --- a/tests/Library/Config/FieldConfigTest.php +++ b/tests/Library/Config/FieldConfigTest.php @@ -15,12 +15,12 @@ class FieldConfigTest extends \PHPUnit_Framework_TestCase { - public function testInvalidParams() + public function testInvalidParams(): void { $fieldConfig = new FieldConfig([ 'name' => 'FirstName', 'type' => new StringType(), - 'resolve' => function ($value, $args = [], $type = null) { + 'resolve' => static function ($value, $args = [], $type = null) : string { return 'John'; } ]); diff --git a/tests/Library/Config/InterfaceTypeConfigTest.php b/tests/Library/Config/InterfaceTypeConfigTest.php index e462bec6..40f3fa32 100644 --- a/tests/Library/Config/InterfaceTypeConfigTest.php +++ b/tests/Library/Config/InterfaceTypeConfigTest.php @@ -19,7 +19,7 @@ class InterfaceTypeConfigTest extends \PHPUnit_Framework_TestCase { - public function testCreation() + public function testCreation(): void { $config = new InterfaceTypeConfig(['name' => 'Test'], null, false); $this->assertEquals($config->getName(), 'Test', 'Normal creation'); @@ -28,17 +28,18 @@ public function testCreation() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testConfigNoFields() + public function testConfigNoFields(): void { ConfigValidator::getInstance()->assertValidConfig( - new InterfaceTypeConfig(['name' => 'Test', 'resolveType' => function () { }], null, true) + new InterfaceTypeConfig(['name' => 'Test', 'resolveType' => static function () : void { + }], null, true) ); } /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testConfigNoResolve() + public function testConfigNoResolve(): void { ConfigValidator::getInstance()->assertValidConfig( new InterfaceTypeConfig(['name' => 'Test', 'fields' => ['id' => new IntType()]], null, true) @@ -48,18 +49,18 @@ public function testConfigNoResolve() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testConfigInvalidResolve() + public function testConfigInvalidResolve(): void { $config = new InterfaceTypeConfig(['name' => 'Test', 'fields' => ['id' => new IntType()]], null, false); $config->resolveType(['invalid object']); } - public function testInterfaces() + public function testInterfaces(): void { $interfaceConfig = new InterfaceTypeConfig([ 'name' => 'Test', 'fields' => ['id' => new IntType()], - 'resolveType' => function ($object) { + 'resolveType' => static function ($object) { return $object->getType(); } ], null, true); diff --git a/tests/Library/Config/ObjectTypeConfigTest.php b/tests/Library/Config/ObjectTypeConfigTest.php index 11819dc6..05daa426 100644 --- a/tests/Library/Config/ObjectTypeConfigTest.php +++ b/tests/Library/Config/ObjectTypeConfigTest.php @@ -16,7 +16,7 @@ class ObjectTypeConfigTest extends \PHPUnit_Framework_TestCase { - public function testCreation() + public function testCreation(): void { $config = new ObjectTypeConfig(['name' => 'Test'], null, false); $this->assertEquals($config->getName(), 'Test', 'Normal creation'); @@ -25,7 +25,7 @@ public function testCreation() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidConfigNoFields() + public function testInvalidConfigNoFields(): void { ConfigValidator::getInstance()->assertValidConfig( new ObjectTypeConfig(['name' => 'Test'], null, true) @@ -35,14 +35,14 @@ public function testInvalidConfigNoFields() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidConfigInvalidInterface() + public function testInvalidConfigInvalidInterface(): void { ConfigValidator::getInstance()->assertValidConfig( new ObjectTypeConfig(['name' => 'Test', 'interfaces' => ['Invalid interface']], null, false) ); } - public function testInterfaces() + public function testInterfaces(): void { $testInterfaceType = new TestInterfaceType(); $config = new ObjectTypeConfig(['name' => 'Test', 'interfaces' => [$testInterfaceType]], null, false); diff --git a/tests/Library/Field/ArgumentsAwareConfigTraitTest.php b/tests/Library/Field/ArgumentsAwareConfigTraitTest.php index e6250dea..55ee7658 100644 --- a/tests/Library/Field/ArgumentsAwareConfigTraitTest.php +++ b/tests/Library/Field/ArgumentsAwareConfigTraitTest.php @@ -17,7 +17,7 @@ class ArgumentsAwareConfigTraitTest extends \PHPUnit_Framework_TestCase { - public function testArguments() + public function testArguments(): void { $argsData = [ 'id' => new IntType() diff --git a/tests/Library/Field/FieldAwareConfigTraitTest.php b/tests/Library/Field/FieldAwareConfigTraitTest.php index 50676020..08a61a66 100644 --- a/tests/Library/Field/FieldAwareConfigTraitTest.php +++ b/tests/Library/Field/FieldAwareConfigTraitTest.php @@ -17,7 +17,7 @@ class FieldAwareConfigTraitTest extends \PHPUnit_Framework_TestCase { - public function testAddField() + public function testAddField(): void { $fieldsData = [ 'id' => [ @@ -32,6 +32,7 @@ public function testAddField() $this->assertTrue($config->hasFields()); $idField = new Field(['name' => 'id', 'type' => new IntType()]); $idField->getName(); + $nameField = new Field(['name' => 'name', 'type' => new StringType()]); $this->assertEquals([ diff --git a/tests/Library/Field/FieldTest.php b/tests/Library/Field/FieldTest.php index e6f62f91..e55f0a2e 100644 --- a/tests/Library/Field/FieldTest.php +++ b/tests/Library/Field/FieldTest.php @@ -24,7 +24,7 @@ class FieldTest extends \PHPUnit_Framework_TestCase { - public function testInlineFieldCreation() + public function testInlineFieldCreation(): void { $field = new Field([ 'name' => 'id', @@ -38,7 +38,7 @@ public function testInlineFieldCreation() $fieldWithResolve = new Field([ 'name' => 'title', 'type' => new StringType(), - 'resolve' => function ($value, array $args, ResolveInfo $info) { + 'resolve' => static function ($value, array $args, ResolveInfo $info) { return $info->getReturnType()->serialize($value); } ]); @@ -50,7 +50,7 @@ public function testInlineFieldCreation() } - public function testObjectFieldCreation() + public function testObjectFieldCreation(): void { $field = new TestField(); $resolveInfo = TestResolveInfo::createTestResolveInfo($field); @@ -61,7 +61,7 @@ public function testObjectFieldCreation() $this->assertEquals('test', $field->resolve('test', [], $resolveInfo)); } - public function testArgumentsTrait() + public function testArgumentsTrait(): void { $testField = new TestField(); $this->assertFalse($testField->hasArguments()); @@ -89,7 +89,7 @@ public function testArgumentsTrait() * @dataProvider invalidFieldProvider * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidFieldParams($fieldConfig) + public function testInvalidFieldParams($fieldConfig): void { $field = new Field($fieldConfig); ConfigValidator::getInstance()->assertValidConfig($field->getConfig()); diff --git a/tests/Library/Field/InputFieldTest.php b/tests/Library/Field/InputFieldTest.php index cd43ed68..b56cc29d 100644 --- a/tests/Library/Field/InputFieldTest.php +++ b/tests/Library/Field/InputFieldTest.php @@ -25,7 +25,7 @@ class InputFieldTest extends \PHPUnit_Framework_TestCase { - private $introspectionQuery = << new ObjectType([ @@ -133,7 +133,7 @@ public function testFieldWithInputFieldArgument() $processor->processPayload($this->introspectionQuery); } - public function testInlineInputFieldCreation() + public function testInlineInputFieldCreation(): void { $field = new InputField([ 'name' => 'id', @@ -149,7 +149,7 @@ public function testInlineInputFieldCreation() } - public function testObjectInputFieldCreation() + public function testObjectInputFieldCreation(): void { $field = new TestInputField(); @@ -159,7 +159,7 @@ public function testObjectInputFieldCreation() $this->assertEquals('default', $field->getDefaultValue()); } - public function testListAsInputField() + public function testListAsInputField(): void { new InputField([ 'name' => 'test', @@ -171,7 +171,7 @@ public function testListAsInputField() * @dataProvider invalidInputFieldProvider * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidInputFieldParams($fieldConfig) + public function testInvalidInputFieldParams($fieldConfig): void { $field = new InputField($fieldConfig); ConfigValidator::getInstance()->assertValidConfig($field->getConfig()); diff --git a/tests/Library/Relay/ArrayConnectionTest.php b/tests/Library/Relay/ArrayConnectionTest.php index fd663978..6128770b 100644 --- a/tests/Library/Relay/ArrayConnectionTest.php +++ b/tests/Library/Relay/ArrayConnectionTest.php @@ -12,7 +12,7 @@ class ArrayConnectionTest extends \PHPUnit_Framework_TestCase { - public function testCursors() + public function testCursors(): void { $offset = 3; $data = ['a', 'b', 'c', 'd', 'e']; @@ -26,7 +26,7 @@ public function testCursors() $this->assertEquals(2, ArrayConnection::cursorToOffsetWithDefault(null, 2)); } - public function testConnectionDefinition() + public function testConnectionDefinition(): void { $data = ['a', 'b', 'c', 'd', 'e']; $edges = []; diff --git a/tests/Library/Relay/CallableFetcherTest.php b/tests/Library/Relay/CallableFetcherTest.php index 044693d6..578f8d47 100644 --- a/tests/Library/Relay/CallableFetcherTest.php +++ b/tests/Library/Relay/CallableFetcherTest.php @@ -14,9 +14,13 @@ class CallableFetcherTest extends \PHPUnit_Framework_TestCase { - public function testMethods() + public function testMethods(): void { - $fetcher = new CallableFetcher(function ($type, $id) { return ['name' => $type . ' Name', 'id' => $id]; }, function ($object) { return $object; }); + $fetcher = new CallableFetcher(static function (string $type, $id) : array { + return ['name' => $type . ' Name', 'id' => $id]; + }, static function ($object) { + return $object; + }); $this->assertEquals([ 'name' => 'User Name', 'id' => 12 diff --git a/tests/Library/Relay/ConnectionTest.php b/tests/Library/Relay/ConnectionTest.php index adbd5867..bdd14020 100644 --- a/tests/Library/Relay/ConnectionTest.php +++ b/tests/Library/Relay/ConnectionTest.php @@ -18,7 +18,7 @@ class ConnectionTest extends \PHPUnit_Framework_TestCase { - public function testConnectionArgs() + public function testConnectionArgs(): void { $this->assertEquals([ 'after' => ['type' => TypeMap::TYPE_STRING], @@ -29,7 +29,7 @@ public function testConnectionArgs() ], Connection::connectionArgs()); } - public function testPageInfoType() + public function testPageInfoType(): void { $type = new PageInfoType(); $this->assertEquals('PageInfo', $type->getName()); @@ -40,7 +40,7 @@ public function testPageInfoType() $this->assertTrue($type->hasField('endCursor')); } - public function testEdgeDefinition() + public function testEdgeDefinition(): void { $edgeType = Connection::edgeDefinition(new StringType(), 'user'); $this->assertEquals('userEdge', $edgeType->getName()); @@ -48,7 +48,7 @@ public function testEdgeDefinition() $this->assertTrue($edgeType->hasField('cursor')); } - public function testConnectionDefinition() + public function testConnectionDefinition(): void { $connection = Connection::connectionDefinition(new TestObjectType(), 'user'); $this->assertEquals($connection->getName(), 'userConnection'); diff --git a/tests/Library/Relay/GlobalIdFieldTest.php b/tests/Library/Relay/GlobalIdFieldTest.php index ddea8876..30f3fa87 100644 --- a/tests/Library/Relay/GlobalIdFieldTest.php +++ b/tests/Library/Relay/GlobalIdFieldTest.php @@ -16,7 +16,7 @@ class GlobalIdFieldTest extends \PHPUnit_Framework_TestCase { - public function testSimpleMethods() + public function testSimpleMethods(): void { $typeName = 'user'; $field = new GlobalIdField($typeName); diff --git a/tests/Library/Relay/MutationTest.php b/tests/Library/Relay/MutationTest.php index 353a93ff..833beddd 100644 --- a/tests/Library/Relay/MutationTest.php +++ b/tests/Library/Relay/MutationTest.php @@ -17,15 +17,14 @@ class MutationTest extends \PHPUnit_Framework_TestCase { - public function testCreation() + public function testCreation(): void { $mutation = RelayMutation::buildMutation('ship', [ 'name' => new StringType() ],[ 'id' => new IdType(), 'name' => new StringType() - ], function($source, $args, $info) { - + ], static function ($source, $args, $info) : void { }); $this->assertEquals('ship', $mutation->getName()); } @@ -33,11 +32,12 @@ public function testCreation() /** * @expectedException \Exception */ - public function testInvalidType() + public function testInvalidType(): void { RelayMutation::buildMutation('ship', [ 'name' => new StringType() - ], new IntType(), function($source, $args, $info) {}); + ], new IntType(), static function ($source, $args, $info) : void { + }); } diff --git a/tests/Library/Relay/NodeFieldTest.php b/tests/Library/Relay/NodeFieldTest.php index 96bab0d3..51bfd401 100644 --- a/tests/Library/Relay/NodeFieldTest.php +++ b/tests/Library/Relay/NodeFieldTest.php @@ -15,9 +15,11 @@ class NodeFieldTest extends \PHPUnit_Framework_TestCase { - public function testMethods() + public function testMethods(): void { - $fetcher = new CallableFetcher(function () { }, function () { }); + $fetcher = new CallableFetcher(static function () : void { + }, static function () : void { + }); $field = new NodeField($fetcher); $this->assertEquals('Fetches an object given its ID', $field->getDescription()); diff --git a/tests/Library/Relay/NodeInterfaceTypeTest.php b/tests/Library/Relay/NodeInterfaceTypeTest.php index 46bfcf5e..ecbf9d34 100644 --- a/tests/Library/Relay/NodeInterfaceTypeTest.php +++ b/tests/Library/Relay/NodeInterfaceTypeTest.php @@ -15,7 +15,7 @@ class NodeInterfaceTypeTest extends \PHPUnit_Framework_TestCase { - public function testMethods() + public function testMethods(): void { $type = new NodeInterfaceType(); $testObject = new TestObjectType(); @@ -25,7 +25,10 @@ public function testMethods() $this->assertNull($type->getFetcher()); $this->assertNull($type->resolveType($testObject)); - $fetcher = new CallableFetcher(function () { }, function () { return new TestObjectType(); }); + $fetcher = new CallableFetcher(static function () : void { + }, static function () : \Youshido\Tests\DataProvider\TestObjectType { + return new TestObjectType(); + }); $type->setFetcher($fetcher); $this->assertEquals($fetcher, $type->getFetcher()); diff --git a/tests/Library/Relay/NodeTest.php b/tests/Library/Relay/NodeTest.php index a9476b6b..79dd25b0 100644 --- a/tests/Library/Relay/NodeTest.php +++ b/tests/Library/Relay/NodeTest.php @@ -14,7 +14,7 @@ class NodeTest extends \PHPUnit_Framework_TestCase { - public function testMethods() + public function testMethods(): void { $global = Node::toGlobalId('user', 1); $fromGlobal = Node::fromGlobalId($global); @@ -35,7 +35,7 @@ public function malformedIdProvider() /** * @dataProvider malformedIdProvider */ - public function testFromGlobalIdThrowsExceptionIfGivenMalformedId($idToCheck) + public function testFromGlobalIdThrowsExceptionIfGivenMalformedId($idToCheck): void { $this->setExpectedException(InvalidArgumentException::class); Node::fromGlobalId($idToCheck); diff --git a/tests/Library/Type/EnumTypeTest.php b/tests/Library/Type/EnumTypeTest.php index c6969712..8ef8d3b3 100644 --- a/tests/Library/Type/EnumTypeTest.php +++ b/tests/Library/Type/EnumTypeTest.php @@ -19,7 +19,7 @@ class EnumTypeTest extends \PHPUnit_Framework_TestCase /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidInlineCreation() + public function testInvalidInlineCreation(): void { new EnumType([]); } @@ -27,7 +27,7 @@ public function testInvalidInlineCreation() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidEmptyParams() + public function testInvalidEmptyParams(): void { $enumField = new EnumType([ 'values' => [] @@ -39,7 +39,7 @@ public function testInvalidEmptyParams() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidValueParams() + public function testInvalidValueParams(): void { $enumField = new EnumType([ 'values' => [ @@ -53,7 +53,7 @@ public function testInvalidValueParams() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testExistingNameParams() + public function testExistingNameParams(): void { $enumField = new EnumType([ 'values' => [ @@ -69,7 +69,7 @@ public function testExistingNameParams() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidNameParams() + public function testInvalidNameParams(): void { $enumField = new EnumType([ 'values' => [ @@ -85,7 +85,7 @@ public function testInvalidNameParams() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testWithoutValueParams() + public function testWithoutValueParams(): void { $enumField = new EnumType([ 'values' => [ @@ -97,7 +97,7 @@ public function testWithoutValueParams() ConfigValidator::getInstance()->assertValidConfig($enumField->getConfig()); } - public function testNormalCreatingParams() + public function testNormalCreatingParams(): void { $valuesData = [ [ @@ -132,7 +132,7 @@ public function testNormalCreatingParams() $this->assertEquals($valuesData, $enumType->getValues()); } - public function testExtendedObject() + public function testExtendedObject(): void { $testEnumType = new TestEnumType(); $this->assertEquals('TestEnum', $testEnumType->getName()); diff --git a/tests/Library/Type/InputObjectTypeTest.php b/tests/Library/Type/InputObjectTypeTest.php index 09320fad..1ad99c23 100644 --- a/tests/Library/Type/InputObjectTypeTest.php +++ b/tests/Library/Type/InputObjectTypeTest.php @@ -25,7 +25,7 @@ class InputObjectTypeTest extends \PHPUnit_Framework_TestCase { - public function testInternal() + public function testInternal(): void { $inputObjectType = new InputObjectType([ 'name' => 'PostData', @@ -41,13 +41,13 @@ public function testInternal() $this->assertFalse($inputObjectType->isValidValue(['title' => null])); } - public function testStandaloneClass() + public function testStandaloneClass(): void { $inputObjectType = new TestInputObjectType(); $this->assertEquals('TestInputObject', $inputObjectType->getName()); } - public function testListOfInputWithNonNull() + public function testListOfInputWithNonNull(): void { $processor = new Processor(new Schema([ 'query' => new ObjectType([ @@ -55,7 +55,7 @@ public function testListOfInputWithNonNull() 'fields' => [ 'empty' => [ 'type' => new StringType(), - 'resolve' => function () { + 'resolve' => static function () { return null; } ] @@ -74,7 +74,7 @@ public function testListOfInputWithNonNull() ])) ], 'type' => new BooleanType(), - 'resolve' => function ($object, $args) { + 'resolve' => static function ($object, $args) : bool { return true; } ] @@ -100,7 +100,7 @@ public function testListOfInputWithNonNull() ); } - public function testNullableInputWithNonNull() + public function testNullableInputWithNonNull(): void { $processor = new Processor(new Schema([ 'query' => new ObjectType([ @@ -108,7 +108,7 @@ public function testNullableInputWithNonNull() 'fields' => [ 'empty' => [ 'type' => new StringType(), - 'resolve' => function () { + 'resolve' => static function () { return null; } ] @@ -127,7 +127,7 @@ public function testNullableInputWithNonNull() ]) ], 'type' => new BooleanType(), - 'resolve' => function ($object, $args) { + 'resolve' => static function ($object, $args) : bool { return true; } ] @@ -143,7 +143,7 @@ public function testNullableInputWithNonNull() ); } - public function testListInsideInputObject() + public function testListInsideInputObject(): void { $processor = new Processor(new Schema([ 'query' => new ObjectType([ @@ -151,7 +151,7 @@ public function testListInsideInputObject() 'fields' => [ 'empty' => [ 'type' => new StringType(), - 'resolve' => function () { + 'resolve' => static function () : void { } ], ] @@ -174,7 +174,7 @@ public function testListInsideInputObject() ] ]) ], - 'resolve' => function () { + 'resolve' => static function () : string { return 'success message'; } ] @@ -200,7 +200,7 @@ public function testListInsideInputObject() $this->assertEquals(['data' => ['createList' => 'success message']], $processor->getResponseData()); } - public function testInputObjectDefaultValue() + public function testInputObjectDefaultValue(): void { $processor = new Processor(new Schema([ 'query' => new ObjectType([ @@ -223,7 +223,7 @@ public function testInputObjectDefaultValue() ], ], ], - 'resolve' => function ($source, $args) { + 'resolve' => static function ($source, array $args) : array { return [ 'limit is ' . $args['paging']['limit'], 'offset is ' . $args['paging']['offset'], @@ -235,6 +235,7 @@ public function testInputObjectDefaultValue() ]), ])); $processor->processPayload('{ cities }'); + $response = $processor->getResponseData(); $this->assertEquals( [ @@ -247,7 +248,7 @@ public function testInputObjectDefaultValue() ); } - public function testInvalidTypeErrors() + public function testInvalidTypeErrors(): void { $processor = new Processor(new Schema([ 'query' => new ObjectType([ @@ -270,7 +271,7 @@ public function testInvalidTypeErrors() ] ]), ], - 'resolve' => function ($source, $args) { + 'resolve' => static function ($source, array $args) : string { return sprintf('%s by %s', $args['title'], $args['userId']); } ], @@ -279,6 +280,7 @@ public function testInvalidTypeErrors() ]), ])); $processor->processPayload('mutation { createPost(object: {title: "Hello world"}) }'); + $response = $processor->getResponseData(); $this->assertEquals( [ diff --git a/tests/Library/Type/InterfaceTypeTest.php b/tests/Library/Type/InterfaceTypeTest.php index 1f444f7b..82a93caf 100644 --- a/tests/Library/Type/InterfaceTypeTest.php +++ b/tests/Library/Type/InterfaceTypeTest.php @@ -19,7 +19,7 @@ class InterfaceTypeTest extends \PHPUnit_Framework_TestCase { - public function testInterfaceMethods() + public function testInterfaceMethods(): void { $interface = new TestInterfaceType(); $this->assertEquals($interface->getNamedType(), $interface->getType()); @@ -47,7 +47,7 @@ public function testInterfaceMethods() 'fields' => [ 'name' => new StringType() ], - 'resolveType' => function ($object) { + 'resolveType' => static function ($object) { return $object; } ]); @@ -59,7 +59,7 @@ public function testInterfaceMethods() $this->assertFalse($interfaceType->isValidValue('invalid object')); } - public function testApplyInterface() + public function testApplyInterface(): void { $extendedType = new TestExtendedType(); diff --git a/tests/Library/Type/ListTypeTest.php b/tests/Library/Type/ListTypeTest.php index fdeb3516..d4f57f12 100644 --- a/tests/Library/Type/ListTypeTest.php +++ b/tests/Library/Type/ListTypeTest.php @@ -17,7 +17,7 @@ class ListTypeTest extends \PHPUnit_Framework_TestCase { - public function testInline() + public function testInline(): void { $listType = new ListType(new StringType()); $this->assertEquals(new StringType(), $listType->getNamedType()); @@ -27,13 +27,13 @@ public function testInline() $this->assertFalse($listType->isValidValue('invalid value')); } - public function testStandaloneClass() + public function testStandaloneClass(): void { $listType = new TestListType(); $this->assertEquals(new StringType(), $listType->getNamedType()); } - public function testListOfInputsWithArguments() + public function testListOfInputsWithArguments(): void { } diff --git a/tests/Library/Type/NonNullTypeTest.php b/tests/Library/Type/NonNullTypeTest.php index c8c80346..eba972e3 100644 --- a/tests/Library/Type/NonNullTypeTest.php +++ b/tests/Library/Type/NonNullTypeTest.php @@ -20,12 +20,12 @@ class NonNullTypeTest extends \PHPUnit_Framework_TestCase /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidParams() + public function testInvalidParams(): void { new NonNullType('invalid param'); } - public function testNonNullType() + public function testNonNullType(): void { $stringType = new StringType(); $nonNullType = new NonNullType(new StringType()); diff --git a/tests/Library/Type/ObjectTypeTest.php b/tests/Library/Type/ObjectTypeTest.php index 43382480..53b63c33 100644 --- a/tests/Library/Type/ObjectTypeTest.php +++ b/tests/Library/Type/ObjectTypeTest.php @@ -24,7 +24,7 @@ class ObjectTypeTest extends \PHPUnit_Framework_TestCase /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testCreatingInvalidObject() + public function testCreatingInvalidObject(): void { new ObjectType([]); } @@ -32,7 +32,7 @@ public function testCreatingInvalidObject() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidNameParam() + public function testInvalidNameParam(): void { $type = new ObjectType([ 'name' => null @@ -43,7 +43,7 @@ public function testInvalidNameParam() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidFieldsParam() + public function testInvalidFieldsParam(): void { $type = new ObjectType([ 'name' => 'SomeName', @@ -55,7 +55,7 @@ public function testInvalidFieldsParam() /** * @expectedException \InvalidArgumentException */ - public function testSerialize() + public function testSerialize(): void { $object = new ObjectType([ 'name' => 'SomeName', @@ -67,7 +67,7 @@ public function testSerialize() } - public function testNormalCreatingParam() + public function testNormalCreatingParam(): void { $objectType = new ObjectType([ 'name' => 'Post', @@ -89,7 +89,7 @@ public function testNormalCreatingParam() $this->assertEquals('Post type description', $objectType->getDescription()); } - public function testFieldsTrait() + public function testFieldsTrait(): void { $idField = new Field(['name' => 'id', 'type' => new IntType()]); $nameField = new Field(['name' => 'name', 'type' => new StringType()]); @@ -113,7 +113,7 @@ public function testFieldsTrait() ], $objectType->getFields()); } - public function testExtendedClass() + public function testExtendedClass(): void { $objectType = new TestObjectType(); $this->assertEquals($objectType->getName(), 'TestObject'); @@ -122,7 +122,7 @@ public function testExtendedClass() $this->assertNull($objectType->getDescription()); } - public function testMutationObjectClass() + public function testMutationObjectClass(): void { $mutation = new TestMutationObjectType(); $this->assertEquals(new StringType(), $mutation->getType()); diff --git a/tests/Library/Type/ScalarExtendTypeTest.php b/tests/Library/Type/ScalarExtendTypeTest.php index 23ab0b57..b6ad8810 100644 --- a/tests/Library/Type/ScalarExtendTypeTest.php +++ b/tests/Library/Type/ScalarExtendTypeTest.php @@ -18,7 +18,7 @@ class ScalarExtendTypeTest extends \PHPUnit_Framework_TestCase { - public function testType() + public function testType(): void { $reportType = new ObjectType([ 'name' => 'Report', @@ -33,7 +33,7 @@ public function testType() 'fields' => [ 'latestReport' => [ 'type' => $reportType, - 'resolve' => function () { + 'resolve' => static function () : array { return [ 'title' => 'Accident #1', 'time' => '13:30:12', diff --git a/tests/Library/Type/ScalarTypeTest.php b/tests/Library/Type/ScalarTypeTest.php index a50e0fea..94c6095e 100644 --- a/tests/Library/Type/ScalarTypeTest.php +++ b/tests/Library/Type/ScalarTypeTest.php @@ -18,7 +18,7 @@ class ScalarTypeTest extends \PHPUnit_Framework_TestCase { - public function testScalarPrimitives() + public function testScalarPrimitives(): void { foreach (TypeFactory::getScalarTypesNames() as $typeName) { $scalarType = TypeFactory::getScalarType($typeName); @@ -32,7 +32,7 @@ public function testScalarPrimitives() $this->assertEquals($scalarType->getType(), $scalarType->getNamedType()); $this->assertNull($scalarType->getConfig()); - foreach (call_user_func(['Youshido\Tests\DataProvider\TestScalarDataProvider', $testDataMethod]) as list($data, $serialized, $isValid)) { + foreach (call_user_func([\Youshido\Tests\DataProvider\TestScalarDataProvider::class, $testDataMethod]) as list($data, $serialized, $isValid)) { $this->assertSerialization($scalarType, $data, $serialized); $this->assertParse($scalarType, $data, $serialized, $typeName); @@ -44,27 +44,29 @@ public function testScalarPrimitives() } } } + try { TypeFactory::getScalarType('invalid type'); - } catch (\Exception $e) { - $this->assertEquals('Configuration problem with type invalid type', $e->getMessage()); + } catch (\Exception $exception) { + $this->assertEquals('Configuration problem with type invalid type', $exception->getMessage()); } + $this->assertEquals('String', (string)new StringType()); } - public function testDateTimeType() + public function testDateTimeType(): void { $dateType = new DateTimeType('Y/m/d H:i:s'); $this->assertEquals('2016/05/31 12:00:00', $dateType->serialize(new \DateTimeImmutable('2016-05-31 12:00pm'))); } - private function assertSerialization(AbstractScalarType $object, $input, $expected) + private function assertSerialization(AbstractScalarType $object, $input, $expected): void { $this->assertEquals($expected, $object->serialize($input), $object->getName() . ' serialize for: ' . serialize($input)); } - private function assertParse(AbstractScalarType $object, $input, $expected, $typeName) + private function assertParse(AbstractScalarType $object, $input, $expected, $typeName): void { $parsed = $object->parseValue($input); if ($parsed instanceof \DateTime) { diff --git a/tests/Library/Type/SchemaDirectivesListTest.php b/tests/Library/Type/SchemaDirectivesListTest.php index 42d95aa5..6d28e138 100644 --- a/tests/Library/Type/SchemaDirectivesListTest.php +++ b/tests/Library/Type/SchemaDirectivesListTest.php @@ -7,7 +7,7 @@ class SchemaDirectivesListTest extends \PHPUnit_Framework_TestCase { - public function testCanAddASingleDirective() + public function testCanAddASingleDirective(): void { $directiveList = new SchemaDirectivesList(); $directiveList->addDirective( @@ -18,7 +18,7 @@ public function testCanAddASingleDirective() $this->assertTrue($directiveList->isDirectiveNameRegistered('testDirective')); } - public function testCanAddMultipleDirectives() + public function testCanAddMultipleDirectives(): void { $directiveList = new SchemaDirectivesList(); $directiveList->addDirectives([ @@ -33,7 +33,7 @@ public function testCanAddMultipleDirectives() $this->assertTrue($directiveList->isDirectiveNameRegistered('testDirectiveTwo')); } - public function testItThrowsExceptionWhenAddingInvalidDirectives() + public function testItThrowsExceptionWhenAddingInvalidDirectives(): void { $this->setExpectedException(\Exception::class, "addDirectives accept only array of directives"); $directiveList = new SchemaDirectivesList(); diff --git a/tests/Library/Type/UnionTypeTest.php b/tests/Library/Type/UnionTypeTest.php index 00dbb300..13789f9f 100644 --- a/tests/Library/Type/UnionTypeTest.php +++ b/tests/Library/Type/UnionTypeTest.php @@ -18,7 +18,7 @@ class UnionTypeTest extends \PHPUnit_Framework_TestCase { - public function testInlineCreation() + public function testInlineCreation(): void { $object = new ObjectType([ 'name' => 'TestObject', @@ -32,7 +32,7 @@ public function testInlineCreation() new TestObjectType(), $object ], - 'resolveType' => function ($type) { + 'resolveType' => static function ($type) { return $type; } ]); @@ -46,7 +46,7 @@ public function testInlineCreation() $this->assertTrue($type->isValidValue(true)); } - public function testObjectCreation() + public function testObjectCreation(): void { $type = new TestUnionType(); @@ -59,7 +59,7 @@ public function testObjectCreation() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidTypesWithScalar() + public function testInvalidTypesWithScalar(): void { $type = new UnionType([ 'name' => 'Car', @@ -67,7 +67,7 @@ public function testInvalidTypesWithScalar() 'types' => [ 'test', new IntType() ], - 'resolveType' => function ($type) { + 'resolveType' => static function ($type) { return $type; } ]); @@ -77,7 +77,7 @@ public function testInvalidTypesWithScalar() /** * @expectedException Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidTypes() + public function testInvalidTypes(): void { $type = new UnionType([ 'name' => 'Car', @@ -85,7 +85,7 @@ public function testInvalidTypes() 'types' => [ new IntType() ], - 'resolveType' => function ($type) { + 'resolveType' => static function ($type) { return $type; } ]); diff --git a/tests/Library/Utilities/ErrorContainerTraitTest.php b/tests/Library/Utilities/ErrorContainerTraitTest.php index 519fee3d..7bcf9a94 100644 --- a/tests/Library/Utilities/ErrorContainerTraitTest.php +++ b/tests/Library/Utilities/ErrorContainerTraitTest.php @@ -25,7 +25,7 @@ protected function setUp() $this->clearErrors(); } - public function testAddHasClearMergeErrors() + public function testAddHasClearMergeErrors(): void { $error = new \Exception('Error'); $this->addError($error); @@ -41,7 +41,7 @@ public function testAddHasClearMergeErrors() $this->assertEquals([$error, $error], $this->getErrors()); } - public function testGetErrorsAsArrayGenericExceptionWithoutCode() + public function testGetErrorsAsArrayGenericExceptionWithoutCode(): void { // Code is zero by default $this->addError(new \Exception('Generic exception')); @@ -52,7 +52,7 @@ public function testGetErrorsAsArrayGenericExceptionWithoutCode() ], $this->getErrorsArray()); } - public function testGetErrorsAsArrayGenericExceptionWithCode() + public function testGetErrorsAsArrayGenericExceptionWithCode(): void { $this->addError(new \Exception('Generic exception with code', 4)); $this->assertEquals([ @@ -63,7 +63,7 @@ public function testGetErrorsAsArrayGenericExceptionWithCode() ], $this->getErrorsArray()); } - public function testGetErrorsAsArrayLocationableException() + public function testGetErrorsAsArrayLocationableException(): void { $this->addError(new SyntaxErrorException('Syntax error', new Location(5, 88))); $this->assertEquals([ @@ -79,7 +79,7 @@ public function testGetErrorsAsArrayLocationableException() ], $this->getErrorsArray()); } - public function testGetErrorsAsArrayExtendedException() + public function testGetErrorsAsArrayExtendedException(): void { $this->addError(new ExtendedException('Extended exception')); $this->assertEquals([ @@ -93,7 +93,7 @@ public function testGetErrorsAsArrayExtendedException() ], $this->getErrorsArray()); } - public function testGetErrorsAsArrayExceptionWithEverything() + public function testGetErrorsAsArrayExceptionWithEverything(): void { $this->addError(new SuperException('Super exception', 3)); $this->assertEquals([ @@ -117,7 +117,7 @@ public function testGetErrorsAsArrayExceptionWithEverything() class ExtendedException extends \Exception implements ExtendedExceptionInterface { - public function getExtensions() + public function getExtensions(): array { return [ 'foo' => 'foo', @@ -128,7 +128,7 @@ public function getExtensions() class SuperException extends \Exception implements LocationableExceptionInterface, ExtendedExceptionInterface { - public function getExtensions() + public function getExtensions(): array { return [ 'foo' => 'foo', @@ -136,7 +136,7 @@ public function getExtensions() ]; } - public function getLocation() + public function getLocation(): \Youshido\GraphQL\Parser\Location { return new Location(6, 10); } diff --git a/tests/Library/Utilities/TypeUtilitiesTest.php b/tests/Library/Utilities/TypeUtilitiesTest.php index f0c33f07..6340be52 100644 --- a/tests/Library/Utilities/TypeUtilitiesTest.php +++ b/tests/Library/Utilities/TypeUtilitiesTest.php @@ -18,7 +18,7 @@ class TypeUtilitiesTest extends \PHPUnit_Framework_TestCase { - public function testTypeService() + public function testTypeService(): void { $this->assertTrue(TypeService::isScalarType(TypeMap::TYPE_STRING)); $this->assertFalse(TypeService::isScalarType('gibberish')); @@ -35,12 +35,12 @@ public function testTypeService() /** * @expectedException \Exception */ - public function testNamedTypeResolverException() + public function testNamedTypeResolverException(): void { TypeService::resolveNamedType(['name' => 'test']); } - public function testIsInputType() + public function testIsInputType(): void { $testType = new ObjectType(['name' => 'test', 'fields' => ['name' => new StringType()]]); $this->assertTrue(TypeService::isInputType(new StringType())); @@ -49,14 +49,14 @@ public function testIsInputType() $this->assertFalse(TypeService::isInputType($testType)); } - public function testIsAbstractType() + public function testIsAbstractType(): void { $this->assertTrue(TypeService::isAbstractType(new TestInterfaceType())); $this->assertFalse(TypeService::isAbstractType(new StringType())); $this->assertFalse(TypeService::isAbstractType('invalid type')); } - public function testGetPropertyValue() { + public function testGetPropertyValue(): void { $arrayData = (new TestObjectType())->getData(); // Test with arrays @@ -80,22 +80,22 @@ public function testGetPropertyValue() { */ class ObjectWithVariousGetters { - public function getName() + public function getName(): string { return 'John'; } - public function getNamedAfter() + public function getNamedAfter(): string { return 'John Doe'; } - public function isTrue() + public function isTrue(): bool { return true; } - public function isFalse() + public function isFalse(): bool { return false; } diff --git a/tests/Library/Validator/RequestValidatorTest.php b/tests/Library/Validator/RequestValidatorTest.php index bff813e1..270334ed 100644 --- a/tests/Library/Validator/RequestValidatorTest.php +++ b/tests/Library/Validator/RequestValidatorTest.php @@ -25,10 +25,8 @@ class RequestValidatorTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Youshido\GraphQL\Exception\Parser\InvalidRequestException * @dataProvider invalidRequestProvider - * - * @param Request $request */ - public function testInvalidRequests(Request $request) + public function testInvalidRequests(Request $request): void { (new RequestValidator())->validate($request); } diff --git a/tests/Library/Validator/SchemaValidatorTest.php b/tests/Library/Validator/SchemaValidatorTest.php index 220c3e03..9f769f23 100644 --- a/tests/Library/Validator/SchemaValidatorTest.php +++ b/tests/Library/Validator/SchemaValidatorTest.php @@ -23,7 +23,7 @@ class SchemaValidatorTest extends \PHPUnit_Framework_TestCase /** * @expectedException \Youshido\GraphQL\Exception\ConfigurationException */ - public function testInvalidSchema() + public function testInvalidSchema(): void { $validator = new SchemaValidator(); $validator->validate(new TestEmptySchema()); @@ -33,7 +33,7 @@ public function testInvalidSchema() * @expectedException \Youshido\GraphQL\Exception\ConfigurationException * @expectedExceptionMessage Implementation of TestInterface is invalid for the field name */ - public function testInvalidInterfacesSimpleType() + public function testInvalidInterfacesSimpleType(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -58,7 +58,7 @@ public function testInvalidInterfacesSimpleType() * @expectedException \Youshido\GraphQL\Exception\ConfigurationException * @expectedExceptionMessage Implementation of TestInterface is invalid for the field name */ - public function testInvalidInterfacesCompositeType() + public function testInvalidInterfacesCompositeType(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -83,7 +83,7 @@ public function testInvalidInterfacesCompositeType() * @expectedException \Youshido\GraphQL\Exception\ConfigurationException * @expectedExceptionMessage Implementation of TestInterface is invalid for the field name */ - public function testInvalidInterfaces() + public function testInvalidInterfaces(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -104,7 +104,7 @@ public function testInvalidInterfaces() $validator->validate($schema); } - public function testValidSchema() + public function testValidSchema(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -126,7 +126,7 @@ public function testValidSchema() try { $validator->validate($schema); $this->assertTrue(true); - } catch (\Exception $e) { + } catch (\Exception $exception) { $this->assertTrue(false); } } diff --git a/tests/Library/Validator/TypeValidationRuleTest.php b/tests/Library/Validator/TypeValidationRuleTest.php index 57e368e1..2e667d34 100644 --- a/tests/Library/Validator/TypeValidationRuleTest.php +++ b/tests/Library/Validator/TypeValidationRuleTest.php @@ -40,7 +40,7 @@ protected function setUp() * * @dataProvider simpleRulesProvider */ - public function testSimpleRules($ruleInfo, $data, $isValid = true) + public function testSimpleRules($ruleInfo, $data, $isValid = true): void { $this->assertEquals($isValid, $this->rule->validate($data, $ruleInfo)); } @@ -55,7 +55,8 @@ public function simpleRulesProvider() [TypeService::TYPE_ANY_OBJECT, new StringType()], [TypeService::TYPE_ANY_OBJECT, null, false], - [TypeService::TYPE_CALLABLE, function () { }], + [TypeService::TYPE_CALLABLE, static function () : void { + }], [TypeService::TYPE_CALLABLE, null, false], [TypeService::TYPE_BOOLEAN, true], @@ -84,7 +85,7 @@ public function simpleRulesProvider() * * @dataProvider complexRuleProvider */ - public function testComplexRules($ruleInfo, $data, $isValid = true) + public function testComplexRules($ruleInfo, $data, $isValid = true): void { $this->assertEquals($isValid, $this->rule->validate($data, $ruleInfo)); } diff --git a/tests/Parser/AstTest.php b/tests/Parser/AstTest.php index 49a8ae92..15bcde1c 100644 --- a/tests/Parser/AstTest.php +++ b/tests/Parser/AstTest.php @@ -23,7 +23,7 @@ class AstTest extends \PHPUnit_Framework_TestCase { - public function testArgument() + public function testArgument(): void { $argument = new Argument('test', new Literal('test', new Location(1,1)), new Location(1,1)); @@ -37,7 +37,7 @@ public function testArgument() $this->assertEquals($argument->getValue(), 'some value'); } - public function testField() + public function testField(): void { $field = new Field('field', null, [], [], new Location(1,1)); @@ -55,7 +55,7 @@ public function testField() $this->assertEquals(['argument' => 'argument value'], $field->getKeyValueArguments()); } - public function testFragment() + public function testFragment(): void { $fields = [ new Field('field', null, [], [], new Location(1,1)) @@ -84,7 +84,7 @@ public function testFragment() $this->assertTrue($fragment->isUsed()); } - public function testFragmentReference() + public function testFragmentReference(): void { $reference = new FragmentReference('shipInfo', new Location(1,1)); @@ -94,7 +94,7 @@ public function testFragmentReference() $this->assertEquals('largeShipInfo', $reference->getName()); } - public function testTypedFragmentReference() + public function testTypedFragmentReference(): void { $fields = [ new Field('id', null, [], [], new Location(1,1)) @@ -117,7 +117,7 @@ public function testTypedFragmentReference() $this->assertEquals($newFields, $reference->getFields()); } - public function testQuery() + public function testQuery(): void { $arguments = [ new Argument('limit', new Literal('10', new Location(1,1)), new Location(1,1)) @@ -151,7 +151,7 @@ public function testQuery() $this->assertTrue($query->hasArguments()); } - public function testArgumentValues() + public function testArgumentValues(): void { $list = new InputList(['a', 'b'], new Location(1,1)); $this->assertEquals(['a', 'b'], $list->getValue()); @@ -169,7 +169,7 @@ public function testArgumentValues() $this->assertEquals('new text', $literal->getValue()); } - public function testVariable() + public function testVariable(): void { $variable = new Variable('id', 'int', false, false, true, new Location(1,1)); @@ -197,7 +197,7 @@ public function testVariable() /** * @expectedException \LogicException */ - public function testVariableLogicException() + public function testVariableLogicException(): void { $variable = new Variable('id', 'int', false, false, true, new Location(1,1)); $variable->getValue(); diff --git a/tests/Parser/ParserTest.php b/tests/Parser/ParserTest.php index 0263d169..1a1a2b06 100644 --- a/tests/Parser/ParserTest.php +++ b/tests/Parser/ParserTest.php @@ -24,7 +24,7 @@ use Youshido\GraphQL\Parser\Token; class TokenizerTestingParser extends Parser { - public function initTokenizerForTesting($source) { + public function initTokenizerForTesting($source): void { $this->initTokenizer($source); } @@ -36,7 +36,7 @@ public function getTokenForTesting() { class ParserTest extends \PHPUnit_Framework_TestCase { - public function testEmptyParser() + public function testEmptyParser(): void { $parser = new Parser(); @@ -53,10 +53,10 @@ public function testEmptyParser() /** * @expectedException Youshido\GraphQL\Exception\Parser\SyntaxErrorException */ - public function testInvalidSelection() + public function testInvalidSelection(): void { $parser = new Parser(); - $data = $parser->parse(' + $parser->parse(' { test { id @@ -68,7 +68,7 @@ public function testInvalidSelection() '); } - public function testComments() + public function testComments(): void { $query = <<initTokenizerForTesting('"' . $graphQLString . '"'); @@ -110,7 +110,7 @@ private function tokenizeStringContents($graphQLString) { } - public function testEscapedStrings() + public function testEscapedStrings(): void { $this->assertEquals([ $this->tokenizeStringContents(""), @@ -143,14 +143,14 @@ public function testEscapedStrings() * @dataProvider wrongQueriesProvider * @expectedException Youshido\GraphQL\Exception\Parser\SyntaxErrorException */ - public function testWrongQueries($query) + public function testWrongQueries($query): void { $parser = new Parser(); $parser->parse($query); } - public function testCommas() + public function testCommas(): void { $parser = new Parser(); $data = $parser->parse('{ foo, ,, , bar }'); @@ -160,7 +160,7 @@ public function testCommas() ], $data['queries']); } - public function testQueryWithNoFields() + public function testQueryWithNoFields(): void { $parser = new Parser(); $data = $parser->parse('{ name }'); @@ -176,7 +176,7 @@ public function testQueryWithNoFields() ], $data); } - public function testQueryWithFields() + public function testQueryWithFields(): void { $parser = new Parser(); $data = $parser->parse('{ post, user { name } }'); @@ -195,7 +195,7 @@ public function testQueryWithFields() ], $data); } - public function testFragmentWithFields() + public function testFragmentWithFields(): void { $parser = new Parser(); $data = $parser->parse(' @@ -222,7 +222,7 @@ public function testFragmentWithFields() ], $data); } - public function testInspectionQuery() + public function testInspectionQuery(): void { $parser = new Parser(); @@ -422,7 +422,7 @@ public function wrongQueriesProvider() /** * @dataProvider mutationProvider */ - public function testMutations($query, $structure) + public function testMutations($query, $structure): void { $parser = new Parser(); @@ -431,7 +431,7 @@ public function testMutations($query, $structure) $this->assertEquals($parsedStructure, $structure); } - public function testTypedFragment() + public function testTypedFragment(): void { $parser = new Parser(); $parsedStructure = $parser->parse(' @@ -553,7 +553,7 @@ public function mutationProvider() /** * @dataProvider queryProvider */ - public function testParser($query, $structure) + public function testParser($query, $structure): void { $parser = new Parser(); $parsedStructure = $parser->parse($query); @@ -831,7 +831,7 @@ public function queryProvider() ]; } - public function testVariablesInQuery() + public function testVariablesInQuery(): void { $parser = new Parser(); @@ -874,7 +874,7 @@ public function testVariablesInQuery() $this->assertArrayNotHasKey('errors', $data); } - public function testVariableDefaultValue() + public function testVariableDefaultValue(): void { // Test with non-null default value $parser = new Parser(); diff --git a/tests/Parser/RequestTest.php b/tests/Parser/RequestTest.php index 49409484..551b40c1 100644 --- a/tests/Parser/RequestTest.php +++ b/tests/Parser/RequestTest.php @@ -16,7 +16,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase { - public function testMethods() + public function testMethods(): void { $fragment1 = new Fragment('fragmentName1', 'test', [], [], new Location(1,1)); $fragment2 = new Fragment('fragmentName2', 'test', [], [], new Location(1,1)); @@ -51,7 +51,7 @@ public function testMethods() $this->assertNull($request->getFragment('unknown fragment')); } - public function testSetVariableParseJson() + public function testSetVariableParseJson(): void { $variables = '{"foo": "bar"}'; $expectedVariableArray = [ 'foo' => 'bar' ]; diff --git a/tests/Parser/VariableTest.php b/tests/Parser/VariableTest.php index 5ff0da38..04e802e2 100644 --- a/tests/Parser/VariableTest.php +++ b/tests/Parser/VariableTest.php @@ -12,7 +12,7 @@ class VariableTest extends \PHPUnit_Framework_TestCase * * @dataProvider variableProvider */ - public function testGetValue($actual, $expected) + public function testGetValue($actual, $expected): void { $var = new Variable('foo', 'bar', false, false, true, new Location(1,1)); $var->setValue($actual); @@ -23,13 +23,13 @@ public function testGetValue($actual, $expected) * @expectedException \LogicException * @expectedExceptionMessage Value is not set for variable "foo" */ - public function testGetNullValueException() + public function testGetNullValueException(): void { $var = new Variable('foo', 'bar', false, false, true, new Location(1,1)); $var->getValue(); } - public function testGetValueReturnsDefaultValueIfNoValueSet() + public function testGetValueReturnsDefaultValueIfNoValueSet(): void { $var = new Variable('foo', 'bar', false, false, true, new Location(1,1)); $var->setDefaultValue('default-value'); @@ -40,7 +40,7 @@ public function testGetValueReturnsDefaultValueIfNoValueSet() ); } - public function testGetValueReturnsSetValueEvenWithDefaultValue() + public function testGetValueReturnsSetValueEvenWithDefaultValue(): void { $var = new Variable('foo', 'bar', false, false, true, new Location(1,1)); $var->setValue('real-value'); @@ -52,7 +52,7 @@ public function testGetValueReturnsSetValueEvenWithDefaultValue() ); } - public function testIndicatesDefaultValuePresent() + public function testIndicatesDefaultValuePresent(): void { $var = new Variable('foo', 'bar', false, false, true, new Location(1,1)); $var->setDefaultValue('default-value'); @@ -62,7 +62,7 @@ public function testIndicatesDefaultValuePresent() ); } - public function testHasNoDefaultValue() + public function testHasNoDefaultValue(): void { $var = new Variable('foo', 'bar', false, false, true, new Location(1,1)); diff --git a/tests/Performance/LoadTest.php b/tests/Performance/LoadTest.php index e110f93c..595a699a 100644 --- a/tests/Performance/LoadTest.php +++ b/tests/Performance/LoadTest.php @@ -19,9 +19,9 @@ class LoadTest extends \PHPUnit_Framework_TestCase { - public function testLoad10k() + public function testLoad10k(): bool { - $time = microtime(true); + microtime(true); $postType = new ObjectType([ 'name' => 'Post', 'fields' => [ @@ -46,6 +46,7 @@ public function testLoad10k() 'name' => 'Author ' . substr(md5(time()), 0, 4) ]; } + $data[] = [ 'id' => $i, 'title' => 'Title of ' . $i, @@ -53,13 +54,13 @@ public function testLoad10k() ]; } - $p = new Processor(new Schema([ + new Processor(new Schema([ 'query' => new ObjectType([ 'name' => 'RootQuery', 'fields' => [ 'posts' => [ 'type' => new ListType($postType), - 'resolve' => function() use ($data) { + 'resolve' => static function () use ($data) { return $data; } ] @@ -67,11 +68,6 @@ public function testLoad10k() ]), ])); return true; - $p->processPayload('{ posts { id, title, authors { name } } }'); - $res = $p->getResponseData(); - echo "Count: " . count($res['data']['posts']) . "\n"; - var_dump($res['data']['posts'][0]); - printf("Test Time: %04f\n", microtime(true) - $time); } } \ No newline at end of file diff --git a/tests/Performance/NPlusOneTest.php b/tests/Performance/NPlusOneTest.php index 5832d331..9e4093cd 100644 --- a/tests/Performance/NPlusOneTest.php +++ b/tests/Performance/NPlusOneTest.php @@ -32,7 +32,7 @@ private function getDataForPosts() ['id' => 3, 'name' => 'Mike'], ]; $posts = []; - for ($i = 0; $i < 10; $i++) { + for ($i = 0; $i < 10; ++$i) { $posts[] = [ 'id' => $i + 1, 'title' => sprintf('Post title $%s', $i), @@ -43,7 +43,7 @@ private function getDataForPosts() return $posts; } - public function testHigherResolver() + public function testHigherResolver(): void { $authorType = new ObjectType([ 'name' => 'Author', diff --git a/tests/Schema/DeferredTest.php b/tests/Schema/DeferredTest.php index a1eb764d..ef8679ee 100644 --- a/tests/Schema/DeferredTest.php +++ b/tests/Schema/DeferredTest.php @@ -8,6 +8,7 @@ namespace Youshido\Tests\Schema; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Config\Schema\SchemaConfig; use Youshido\GraphQL\Execution\DeferredResolver; use Youshido\GraphQL\Execution\Processor; @@ -42,7 +43,7 @@ public function query(array $ids); class DeferredQueryBuffer { - protected $database; + protected \Youshido\Tests\Schema\DeferredDatabase $database; protected $buffer = []; @@ -75,6 +76,7 @@ protected function fetch($resultId) foreach ($query as $id) { $this->results[$index][$id] = $result[$id]; } + unset($this->buffer[$index]); } } @@ -86,10 +88,7 @@ protected function fetch($resultId) class DeferredUserType extends AbstractObjectType { - /** - * @var \Youshido\Tests\Schema\DeferredQueryBuffer - */ - protected $database; + protected \Youshido\Tests\Schema\DeferredQueryBuffer $database; public function __construct(DeferredQueryBuffer $database) { @@ -98,14 +97,14 @@ public function __construct(DeferredQueryBuffer $database) } - public function build($config) + public function build(ObjectTypeConfig $config): void { $config->addField( new Field( [ 'name' => 'name', 'type' => new StringType(), - 'resolve' => function ($value) { + 'resolve' => static function (array $value) { return $value['name']; }, ] @@ -117,7 +116,7 @@ public function build($config) [ 'name' => 'friends', 'type' => new ListType(new DeferredUserType($this->database)), - 'resolve' => function ($value) { + 'resolve' => function (array $value): \Youshido\GraphQL\Execution\DeferredResolver { return new DeferredResolver( $this->database->add($value['friends']) ); @@ -131,7 +130,7 @@ public function build($config) [ 'name' => 'foes', 'type' => new ListType(new DeferredUserType($this->database)), - 'resolve' => function ($value) { + 'resolve' => function (array $value): \Youshido\GraphQL\Execution\DeferredResolver { return new DeferredResolver( $this->database->add($value['foes']) ); @@ -151,7 +150,7 @@ public function __construct(DeferredQueryBuffer $buffer) [ 'name' => 'users', 'type' => new ListType(new DeferredUserType($buffer)), - 'resolve' => function ($value, $args) use ($buffer) { + 'resolve' => static function ($value, array $args) use ($buffer) : \Youshido\GraphQL\Execution\DeferredResolver { return new DeferredResolver($buffer->add($args['ids'])); }, ] @@ -176,7 +175,7 @@ public function __construct(DeferredQueryBuffer $buffer) } - public function build(SchemaConfig $config) + public function build(SchemaConfig $config): void { } @@ -206,7 +205,7 @@ protected function query($query, DeferredQueryBuffer $buffer) /** * Test a simple single deferred field. */ - public function testSingleResolve() + public function testSingleResolve(): void { $query = 'query { users(ids: ["a", "b"]) { @@ -244,7 +243,7 @@ public function testSingleResolve() /** * Test if multiple calls to the same field result in a single query. */ - public function testMultiResolve() + public function testMultiResolve(): void { $query = 'query { @@ -290,7 +289,7 @@ public function testMultiResolve() /** * Test if recursive deferred resolvers work properly. */ - public function testRecursiveResolve() + public function testRecursiveResolve(): void { $query = 'query { @@ -344,7 +343,7 @@ public function testRecursiveResolve() /** * Test if multiple deferred resolvers are optimized into two queries. */ - public function testMultiRecursiveResolve() + public function testMultiRecursiveResolve(): void { $query = 'query { diff --git a/tests/Schema/FragmentsTest.php b/tests/Schema/FragmentsTest.php index 72bcbd7b..e881ddd6 100644 --- a/tests/Schema/FragmentsTest.php +++ b/tests/Schema/FragmentsTest.php @@ -19,7 +19,7 @@ class UserType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config->addFields([ 'id' => new IdType(), @@ -32,7 +32,7 @@ public function build($config) class CourtReservation extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config->addFields([ 'id' => new IdType(), @@ -46,7 +46,7 @@ public function build($config) ]); } - public function getInterfaces() + public function getInterfaces(): array { return [new ReservationInterface()]; } @@ -55,7 +55,7 @@ public function getInterfaces() class ClassReservation extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config->addFields([ 'id' => new IdType(), @@ -63,7 +63,7 @@ public function build($config) ]); } - public function getInterfaces() + public function getInterfaces(): array { return [new ReservationInterface()]; } @@ -71,12 +71,12 @@ public function getInterfaces() class ReservationInterface extends AbstractInterfaceType { - public function resolveType($object) + public function resolveType($object): \Youshido\Tests\Schema\CourtReservation|\Youshido\Tests\Schema\ClassReservation { - return strpos($object['id'], 'cl') === false ? new CourtReservation() : new ClassReservation(); + return strpos((string) $object['id'], 'cl') === false ? new CourtReservation() : new ClassReservation(); } - public function build($config) + public function build(InterfaceTypeConfig $config): void { $config->addFields([ 'id' => new IdType() @@ -95,7 +95,7 @@ class FragmentsTest extends \PHPUnit_Framework_TestCase * @param $expected * @param $variables */ - public function testVariables($query, $expected, $variables) + public function testVariables($query, $expected, $variables): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -103,7 +103,7 @@ public function testVariables($query, $expected, $variables) 'fields' => [ 'user' => [ 'type' => new UserType(), - 'resolve' => function ($args) { + 'resolve' => static function ($args) : array { return [ 'id' => 'user-id-1', 'fullName' => 'Alex', @@ -137,6 +137,7 @@ public function testVariables($query, $expected, $variables) $processor = new Processor($schema); $processor->processPayload($query, $variables); + $result = $processor->getResponseData(); $this->assertEquals($expected, $result); @@ -209,7 +210,7 @@ public function queries() ]; } - public function testSimpleFragment() + public function testSimpleFragment(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -217,7 +218,7 @@ public function testSimpleFragment() 'fields' => [ 'user' => [ 'type' => new UserType(), - 'resolve' => function ($args) { + 'resolve' => static function ($args) : array { return [ 'id' => 'user-id-1', 'fullName' => 'Alex', @@ -247,6 +248,7 @@ public function testSimpleFragment() $processor = new Processor($schema); $processor->processPayload($query); + $result = $processor->getResponseData(); $expected = ['data' => ['User1' => ['fullName' => 'Alex'], 'User2' => ['fullName' => 'Alex']]]; diff --git a/tests/Schema/InputObjectDefaultValuesTest.php b/tests/Schema/InputObjectDefaultValuesTest.php index a13c60d3..61555848 100644 --- a/tests/Schema/InputObjectDefaultValuesTest.php +++ b/tests/Schema/InputObjectDefaultValuesTest.php @@ -16,7 +16,7 @@ class InputObjectDefaultValuesTest extends \PHPUnit_Framework_TestCase { - public function testDefaultEnum() + public function testDefaultEnum(): void { $enumType = new EnumType([ 'name' => 'InternalStatus', @@ -49,7 +49,7 @@ public function testDefaultEnum() ] ]) ], - 'resolve' => function ($source, $args) { + 'resolve' => static function ($source, array $args) : string { return sprintf('Result with level %s and status %s', $args['statObject']['level'], $args['statObject']['status'] ); @@ -62,7 +62,7 @@ public function testDefaultEnum() 'status' => $enumType ] ]), - 'resolve' => function() { + 'resolve' => static function () : array { return [ 'status' => null ]; @@ -75,6 +75,7 @@ public function testDefaultEnum() $processor = new Processor($schema); $processor->processPayload('{ stringQuery(statObject: { level: 1 }) }'); + $result = $processor->getResponseData(); $this->assertEquals(['data' => [ 'stringQuery' => 'Result with level 1 and status 1' diff --git a/tests/Schema/InputParseTest.php b/tests/Schema/InputParseTest.php index d3bc3b86..2faa325f 100644 --- a/tests/Schema/InputParseTest.php +++ b/tests/Schema/InputParseTest.php @@ -18,7 +18,7 @@ class InputParseTest extends \PHPUnit_Framework_TestCase * @param $query * @param $expected */ - public function testDateInput($query, $expected) + public function testDateInput($query, $expected): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -30,7 +30,7 @@ public function testDateInput($query, $expected) 'from' => new DateTimeType('Y-m-d H:i:s'), 'fromtz' => new DateTimeTzType(), ], - 'resolve' => function ($source, $args) { + 'resolve' => static function ($source, array $args) : string { return sprintf('Result with %s date and %s tz', empty($args['from']) ? 'default' : $args['from']->format('Y-m-d H:i:s'), empty($args['fromtz']) ? 'default' : $args['fromtz']->format('r') @@ -43,6 +43,7 @@ public function testDateInput($query, $expected) $processor = new Processor($schema); $processor->processPayload($query); + $result = $processor->getResponseData(); $this->assertEquals($expected, $result); diff --git a/tests/Schema/IntrospectionTest.php b/tests/Schema/IntrospectionTest.php index 7bdafee0..ae25b089 100644 --- a/tests/Schema/IntrospectionTest.php +++ b/tests/Schema/IntrospectionTest.php @@ -27,7 +27,7 @@ class IntrospectionTest extends \PHPUnit_Framework_TestCase { - private $introspectionQuery = <<addQueryField(new Field([ @@ -139,7 +139,7 @@ public function testPredefinedQueries($query, $expectedResponse) 'description' => 'latest description', 'deprecationReason' => 'for test', 'isDeprecated' => true, - 'resolve' => function () { + 'resolve' => static function () : array { return [ 'id' => 1, 'name' => 'Alex' @@ -150,6 +150,7 @@ public function testPredefinedQueries($query, $expectedResponse) $processor = new Processor($schema); $processor->processPayload($query); + $responseData = $processor->getResponseData(); $this->assertEquals($expectedResponse, $responseData); @@ -285,7 +286,7 @@ interfaces { ]; } - public function testCombinedFields() + public function testCombinedFields(): void { $schema = new TestEmptySchema(); @@ -295,8 +296,7 @@ public function testCombinedFields() 'id' => ['type' => new IntType()], 'name' => ['type' => new IntType()], ], - 'resolveType' => function ($type) { - + 'resolveType' => static function ($type) : void { } ]); @@ -323,8 +323,7 @@ public function testCombinedFields() $unionType = new UnionType([ 'name' => 'UnionType', 'types' => [$object1, $object2], - 'resolveType' => function () { - + 'resolveType' => static function () : void { } ]); @@ -334,7 +333,7 @@ public function testCombinedFields() 'args' => [ 'id' => ['type' => TypeMap::TYPE_INT] ], - 'resolve' => function () { + 'resolve' => static function () : array { return [ 'id' => 1, 'name' => 'Alex' @@ -360,7 +359,7 @@ public function testCombinedFields() ] ]) ], - 'resolve' => function () { + 'resolve' => static function () { return null; } ])); @@ -368,13 +367,14 @@ public function testCombinedFields() $processor = new Processor($schema); $processor->processPayload($this->introspectionQuery); + $responseData = $processor->getResponseData(); /** strange that this test got broken after I fixed the field resolve behavior */ $this->assertArrayNotHasKey('errors', $responseData); } - public function testCanIntrospectDirectives() + public function testCanIntrospectDirectives(): void { $schema = new TestSchema(); $schema->getDirectiveList()->addDirectives([ @@ -429,6 +429,7 @@ public function testCanIntrospectDirectives() $processor = new Processor($schema); $processor->processPayload($this->introspectionQuery); + $responseData = $processor->getResponseData(); $this->assertArrayNotHasKey('errors', $responseData); } diff --git a/tests/Schema/NonNullableTest.php b/tests/Schema/NonNullableTest.php index 8069cc35..35f09d7e 100644 --- a/tests/Schema/NonNullableTest.php +++ b/tests/Schema/NonNullableTest.php @@ -18,14 +18,14 @@ class uid { - private $uid; + private readonly string $uid; public function __construct($uid) { $this->uid = $uid; } - public function __toString() + public function __toString(): string { return $this->uid; } @@ -40,7 +40,7 @@ class NonNullableTest extends \PHPUnit_Framework_TestCase * @param $query * @param $expected */ - public function testNullableResolving($query, $expected) + public function testNullableResolving($query, $expected): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -48,13 +48,13 @@ public function testNullableResolving($query, $expected) 'fields' => [ 'nonNullScalar' => [ 'type' => new NonNullType(new IntType()), - 'resolve' => function () { + 'resolve' => static function () { return null; }, ], 'nonNullList' => [ 'type' => new NonNullType(new ListType(new IntType())), - 'resolve' => function () { + 'resolve' => static function () { return null; } ], @@ -66,7 +66,7 @@ public function testNullableResolving($query, $expected) 'name' => new StringType(), ] ])), - 'resolve' => function () { + 'resolve' => static function () : array { return [ 'id' => new uid('6cfb044c-9c0a-4ddd-9ef8-a0b940818db3'), 'name' => 'Alex' @@ -75,7 +75,7 @@ public function testNullableResolving($query, $expected) ], 'nonNullListOfNpnNull' => [ 'type' => new NonNullType(new ListType(new NonNullType(new IntType()))), - 'resolve' => function () { + 'resolve' => static function () : array { return [1, null]; } ], @@ -84,7 +84,7 @@ public function testNullableResolving($query, $expected) 'ids' => new NonNullType(new ListType(new IntType())) ], 'type' => new IntType(), - 'resolve' => function () { + 'resolve' => static function () : int { return 1; } ], @@ -93,7 +93,7 @@ public function testNullableResolving($query, $expected) 'ids' => new NonNullType(new ListType(new NonNullType(new IntType()))) ], 'type' => new IntType(), - 'resolve' => function () { + 'resolve' => static function () : int { return 1; } ], @@ -103,6 +103,7 @@ public function testNullableResolving($query, $expected) $processor = new Processor($schema); $processor->processPayload($query); + $result = $processor->getResponseData(); $this->assertEquals($expected, $result); diff --git a/tests/Schema/ProcessorTest.php b/tests/Schema/ProcessorTest.php index 545416c7..6a7ae05e 100644 --- a/tests/Schema/ProcessorTest.php +++ b/tests/Schema/ProcessorTest.php @@ -34,15 +34,15 @@ class ProcessorTest extends \PHPUnit_Framework_TestCase { - private $_counter = 0; + private int $_counter = 0; - public function testInit() + public function testInit(): void { $processor = new Processor(new TestEmptySchema()); $this->assertEquals([['message' => 'Schema has to have fields']], $processor->getExecutionContext()->getErrorsArray()); } - public function testEmptyQueries() + public function testEmptyQueries(): void { $processor = new Processor(new TestSchema()); $processor->processPayload(''); @@ -58,7 +58,7 @@ public function testEmptyQueries() } - public function testNestedVariables() + public function testNestedVariables(): void { $processor = new Processor(new TestSchema()); $noArgsQuery = '{ me { echo(value:"foo") } }'; @@ -88,7 +88,7 @@ public function testNestedVariables() $this->assertArrayNotHasKey('errors', $processor->getResponseData()); } - public function testNullListVariable() + public function testNullListVariable(): void { $processor = new Processor(new TestSchema()); $processor->processPayload( @@ -102,7 +102,7 @@ public function testNullListVariable() $this->assertArrayNotHasKey('errors', $processor->getResponseData()); } - public function testListNullResponse() + public function testListNullResponse(): void { $processor = new Processor(new Schema([ 'query' => new ObjectType([ @@ -110,7 +110,7 @@ public function testListNullResponse() 'fields' => [ 'list' => [ 'type' => new ListType(new StringType()), - 'resolve' => function () { + 'resolve' => static function () { return null; } ] @@ -122,7 +122,7 @@ public function testListNullResponse() } - public function testSubscriptionNullResponse() + public function testSubscriptionNullResponse(): void { $processor = new Processor(new Schema([ 'query' => new ObjectType([ @@ -130,7 +130,7 @@ public function testSubscriptionNullResponse() 'fields' => [ 'list' => [ 'type' => new ListType(new StringType()), - 'resolve' => function () { + 'resolve' => static function () { return null; } ] @@ -141,7 +141,7 @@ public function testSubscriptionNullResponse() $this->assertEquals(['data' => ['__schema' => ['subscriptionType' => null]]], $data); } - public function testSchemaOperations() + public function testSchemaOperations(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -156,13 +156,13 @@ public function testSchemaOperations() 'args' => [ 'shorten' => new BooleanType() ], - 'resolve' => function ($value, $args) { + 'resolve' => static function (array $value, array $args) { return empty($args['shorten']) ? $value['firstName'] : $value['firstName']; } ], 'id_alias' => [ 'type' => new IdType(), - 'resolve' => function ($value) { + 'resolve' => static function (array $value) { return $value['id']; } ], @@ -170,14 +170,13 @@ public function testSchemaOperations() 'code' => new StringType(), ] ]), - 'resolve' => function ($value, $args) { + 'resolve' => static function ($value, array $args) : array { $data = ['id' => '123', 'firstName' => 'John', 'code' => '007']; if (!empty($args['upper'])) { foreach ($data as $key => $value) { $data[$key] = strtoupper($value); } } - return $data; }, 'args' => [ @@ -189,19 +188,19 @@ public function testSchemaOperations() ], 'randomUser' => [ 'type' => new TestObjectType(), - 'resolve' => function () { + 'resolve' => static function () : array { return ['invalidField' => 'John']; } ], 'invalidValueQuery' => [ 'type' => new TestObjectType(), - 'resolve' => function () { + 'resolve' => static function () : string { return 'stringValue'; } ], 'labels' => [ 'type' => new ListType(new StringType()), - 'resolve' => function () { + 'resolve' => static function () : array { return ['one', 'two']; } ] @@ -238,7 +237,7 @@ public function testSchemaOperations() ->addField(new Field([ 'name' => 'increaseCounter', 'type' => new IntType(), - 'resolve' => function ($value, $args, ResolveInfo $info) { + 'resolve' => function ($value, array $args, ResolveInfo $info): float|int|array { return $this->_counter += $args['amount']; }, 'args' => [ @@ -250,13 +249,13 @@ public function testSchemaOperations() ]))->addField(new Field([ 'name' => 'invalidResolveTypeMutation', 'type' => new NonNullType(new IntType()), - 'resolve' => function () { + 'resolve' => static function () { return null; } ]))->addField(new Field([ 'name' => 'interfacedMutation', 'type' => new TestInterfaceType(), - 'resolve' => function () { + 'resolve' => static function () : array { return ['name' => 'John']; } ])); @@ -362,7 +361,7 @@ public function testSchemaOperations() $this->assertEquals(['data' => ['user' => ['name' => 'John']]], $processor->getResponseData()); } - public function testEnumType() + public function testEnumType(): void { $processor = new Processor(new Schema([ 'query' => new ObjectType([ @@ -385,7 +384,7 @@ public function testEnumType() ])) ], 'type' => new StringType(), - 'resolve' => function ($value, $args) { + 'resolve' => static function ($value, array $args) { return $args['argument1']; } ] @@ -394,6 +393,7 @@ public function testEnumType() ])); $processor->processPayload('{ test }'); + $response = $processor->getResponseData(); $this->assertEquals([ 'data' => ['test' => null], @@ -430,7 +430,7 @@ public function testEnumType() $this->assertEquals(['data' => ['alias' => 'val1']], $response); } - public function testListEnumsSchemaOperations() + public function testListEnumsSchemaOperations(): void { $processor = new Processor(new Schema([ 'query' => new ObjectType([ @@ -438,43 +438,43 @@ public function testListEnumsSchemaOperations() 'fields' => [ 'listQuery' => [ 'type' => new ListType(new TestEnumType()), - 'resolve' => function () { + 'resolve' => static function () : string { return 'invalid list'; } ], 'listEnumQuery' => [ 'type' => new ListType(new TestEnumType()), - 'resolve' => function () { + 'resolve' => static function () : array { return ['invalid enum']; } ], 'invalidEnumQuery' => [ 'type' => new TestEnumType(), - 'resolve' => function () { + 'resolve' => static function () : string { return 'invalid enum'; } ], 'enumQuery' => [ 'type' => new TestEnumType(), - 'resolve' => function () { + 'resolve' => static function () : int { return 1; } ], 'invalidNonNullQuery' => [ 'type' => new NonNullType(new IntType()), - 'resolve' => function () { + 'resolve' => static function () { return null; } ], 'invalidNonNullInsideQuery' => [ 'type' => new NonNullType(new IntType()), - 'resolve' => function () { + 'resolve' => static function () : string { return 'hello'; } ], 'objectQuery' => [ 'type' => new TestObjectType(), - 'resolve' => function () { + 'resolve' => static function () : array { return ['name' => 'John']; } ], @@ -486,7 +486,7 @@ public function testListEnumsSchemaOperations() 'enum' => new TestEnumType(), ], ]), - 'resolve' => function () { + 'resolve' => static function () : array { return [ 'object' => [ 'name' => 'John' @@ -541,7 +541,7 @@ public function testListEnumsSchemaOperations() $this->assertEquals(['data' => ['test' => ['object' => ['name' => 'John']]]], $processor->getResponseData()); } - public function testTypedFragment() + public function testTypedFragment(): void { $object1 = new ObjectType([ @@ -568,18 +568,17 @@ public function testTypedFragment() $union = new UnionType([ 'name' => 'TestUnion', 'types' => [$object1, $object2], - 'resolveType' => function ($object) use ($object1, $object2) { + 'resolveType' => static function (array $object) use ($object1, $object2) { if (isset($object['id'])) { return $object1; } - return $object2; } ]); $invalidUnion = new UnionType([ 'name' => 'TestUnion', 'types' => [$object1, $object2], - 'resolveType' => function ($object) use ($object3) { + 'resolveType' => static function ($object) use ($object3) { return $object3; } ]); @@ -593,7 +592,7 @@ public function testTypedFragment() 'type' => ['type' => 'string'] ], 'cost' => 10, - 'resolve' => function ($value, $args) { + 'resolve' => static function ($value, array $args) { if ($args['type'] == 'object1') { return [ 'id' => 43 @@ -607,7 +606,7 @@ public function testTypedFragment() ], 'invalidUnion' => [ 'type' => $invalidUnion, - 'resolve' => function () { + 'resolve' => static function () : array { return ['name' => 'name resolved']; } ], @@ -666,7 +665,7 @@ public function testTypedFragment() $this->assertEquals(10 + 13 + 1, $visitor->getMemo()); } - public function testContainer() + public function testContainer(): void { $container = new Container(); $container->set('user', ['name' => 'Alex']); @@ -677,7 +676,7 @@ public function testContainer() 'fields' => [ 'currentUser' => [ 'type' => new StringType(), - 'resolve' => function ($source, $args, ResolveInfo $info) { + 'resolve' => static function ($source, $args, ResolveInfo $info) { return $info->getContainer()->get('user')['name']; } ] @@ -692,7 +691,7 @@ public function testContainer() $this->assertEquals(['data' => ['currentUser' => 'Alex']], $processor->processPayload('{ currentUser }')->getResponseData()); } - public function testComplexityReducer() + public function testComplexityReducer(): void { $schema = new Schema( [ @@ -710,7 +709,7 @@ public function testComplexityReducer() 'args' => [ 'shorten' => new BooleanType() ], - 'resolve' => function ($value, $args) { + 'resolve' => static function (array $value, array $args) { return empty($args['shorten']) ? $value['firstName'] : $value['firstName']; } ], @@ -719,22 +718,19 @@ public function testComplexityReducer() 'likes' => [ 'type' => new IntType(), 'cost' => 10, - 'resolve' => function () { + 'resolve' => static function () : int { return 42; } ] ] ] ), - 'cost' => function ($args, $context, $childCost) { + 'cost' => static function (array $args, $context, $childCost) : int|float { $argsCost = isset($args['cost']) ? $args['cost'] : 1; - return 1 + $argsCost * $childCost; }, - 'resolve' => function ($value, $args) { - $data = ['firstName' => 'John', 'code' => '007']; - - return $data; + 'resolve' => static function ($value, $args) : array { + return ['firstName' => 'John', 'code' => '007']; }, 'args' => [ 'cost' => [ @@ -779,7 +775,7 @@ public function testComplexityReducer() foreach (range(1, 5) as $cost_multiplier) { $visitor = new MaxComplexityQueryVisitor(1000); // arbitrarily high cost - $processor->processPayload("{ me (cost: $cost_multiplier) { firstName, lastName, code, likes } }", ['cost' => $cost_multiplier], [$visitor]); + $processor->processPayload(sprintf('{ me (cost: %s) { firstName, lastName, code, likes } }', $cost_multiplier), ['cost' => $cost_multiplier], [$visitor]); $expected = 1 + 13 * (1 + $cost_multiplier); $this->assertEquals($expected, $visitor->getMemo()); } diff --git a/tests/Schema/ResolveInfoTest.php b/tests/Schema/ResolveInfoTest.php index af903980..e3bad06d 100644 --- a/tests/Schema/ResolveInfoTest.php +++ b/tests/Schema/ResolveInfoTest.php @@ -19,7 +19,7 @@ class ResolveInfoTest extends \PHPUnit_Framework_TestCase { - public function testMethods() + public function testMethods(): void { $fieldAst = new FieldAST('name', null, [], [], new Location(1,1)); $field = new Field(['name' => 'id', 'type' => new IntType()]); diff --git a/tests/Schema/SchemaTest.php b/tests/Schema/SchemaTest.php index 5c1c75fe..a21f558e 100644 --- a/tests/Schema/SchemaTest.php +++ b/tests/Schema/SchemaTest.php @@ -22,13 +22,13 @@ class SchemaTest extends \PHPUnit_Framework_TestCase { - public function testStandaloneEmptySchema() + public function testStandaloneEmptySchema(): void { $schema = new TestEmptySchema(); $this->assertFalse($schema->getQueryType()->hasFields()); } - public function testStandaloneSchema() + public function testStandaloneSchema(): void { $schema = new TestSchema(); $this->assertTrue($schema->getQueryType()->hasFields()); @@ -36,13 +36,13 @@ public function testStandaloneSchema() $this->assertEquals(1, count($schema->getMutationType()->getFields())); - $schema->addMutationField('changeUser', ['type' => new TestObjectType(), 'resolve' => function () { + $schema->addMutationField('changeUser', ['type' => new TestObjectType(), 'resolve' => static function () : void { }]); $this->assertEquals(2, count($schema->getMutationType()->getFields())); } - public function testSchemaWithoutClosuresSerializable() + public function testSchemaWithoutClosuresSerializable(): void { $schema = new TestEmptySchema(); $schema->getQueryType()->addField('randomInt', [ @@ -59,7 +59,7 @@ public function testSchemaWithoutClosuresSerializable() $this->assertEquals(1, count($unserialized->getQueryType()->getFields())); } - public function testCustomTypes() + public function testCustomTypes(): void { $authorType = null; @@ -68,7 +68,7 @@ public function testCustomTypes() 'fields' => [ 'name' => new StringType(), ], - 'resolveType' => function () use ($authorType) { + 'resolveType' => static function () use ($authorType) { return $authorType; } ]); @@ -87,7 +87,7 @@ public function testCustomTypes() 'fields' => [ 'user' => [ 'type' => $userInterface, - 'resolve' => function () { + 'resolve' => static function () : array { return [ 'name' => 'Alex' ]; diff --git a/tests/Schema/VariablesTest.php b/tests/Schema/VariablesTest.php index c04ab334..9e613dc2 100644 --- a/tests/Schema/VariablesTest.php +++ b/tests/Schema/VariablesTest.php @@ -12,7 +12,7 @@ class VariablesTest extends \PHPUnit_Framework_TestCase { - public function testInvalidNullableList() + public function testInvalidNullableList(): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -23,7 +23,7 @@ public function testInvalidNullableList() 'args' => [ 'ids' => new ListType(new NonNullType(new IdType())), ], - 'resolve' => function () { + 'resolve' => static function () : string { return 'item'; }, ], @@ -89,7 +89,7 @@ public function testInvalidNullableList() * @param $expected * @param $variables */ - public function testVariables($query, $expected, $variables) + public function testVariables($query, $expected, $variables): void { $schema = new Schema([ 'query' => new ObjectType([ @@ -100,7 +100,7 @@ public function testVariables($query, $expected, $variables) 'args' => [ 'sortOrder' => new StringType(), ], - 'resolve' => function ($args) { + 'resolve' => static function (array $args) : string { return sprintf('Result with %s order', empty($args['sortOrder']) ? 'default' : $args['sortOrder']); }, ], @@ -110,6 +110,7 @@ public function testVariables($query, $expected, $variables) $processor = new Processor($schema); $processor->processPayload($query, $variables); + $result = $processor->getResponseData(); $this->assertEquals($expected, $result); diff --git a/tests/StarWars/Schema/CharacterInterface.php b/tests/StarWars/Schema/CharacterInterface.php index 273aaf14..97627231 100644 --- a/tests/StarWars/Schema/CharacterInterface.php +++ b/tests/StarWars/Schema/CharacterInterface.php @@ -8,6 +8,7 @@ namespace Youshido\Tests\StarWars\Schema; +use Youshido\GraphQL\Config\Object\InterfaceTypeConfig; use Youshido\GraphQL\Type\InterfaceType\AbstractInterfaceType; use Youshido\GraphQL\Type\ListType\ListType; use Youshido\GraphQL\Type\NonNullType; @@ -16,31 +17,31 @@ class CharacterInterface extends AbstractInterfaceType { - public function build($config) + public function build(InterfaceTypeConfig $config): void { $config ->addField('id', new NonNullType(new IdType())) ->addField('name', new NonNullType(new StringType())) ->addField('friends', [ 'type' => new ListType(new CharacterInterface()), - 'resolve' => function ($value) { + 'resolve' => static function (array $value) { return $value['friends']; } ]) ->addField('appearsIn', new ListType(new EpisodeEnum())); } - public function getDescription() + public function getDescription(): string { return 'A character in the Star Wars Trilogy'; } - public function getName() + public function getName(): string { return 'Character'; } - public function resolveType($object) + public function resolveType($object): \Youshido\Tests\StarWars\Schema\HumanType|\Youshido\Tests\StarWars\Schema\DroidType|null { $humans = StarWarsData::humans(); $droids = StarWarsData::droids(); diff --git a/tests/StarWars/Schema/DroidType.php b/tests/StarWars/Schema/DroidType.php index 7b4101df..b7a9d6d5 100644 --- a/tests/StarWars/Schema/DroidType.php +++ b/tests/StarWars/Schema/DroidType.php @@ -8,6 +8,7 @@ namespace Youshido\Tests\StarWars\Schema; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\TypeMap; class DroidType extends HumanType @@ -16,16 +17,16 @@ class DroidType extends HumanType /** * @return String type name */ - public function getName() + public function getName(): string { return 'Droid'; } - public function build($config) + public function build(ObjectTypeConfig $config): void { parent::build($config); - $config->getField('friends')->getConfig()->set('resolve', function ($droid) { + $config->getField('friends')->getConfig()->set('resolve', static function ($droid) { return StarWarsData::getFriends($droid); }); @@ -33,7 +34,7 @@ public function build($config) ->addField('primaryFunction', TypeMap::TYPE_STRING); } - public function getInterfaces() + public function getInterfaces(): array { return [new CharacterInterface()]; } diff --git a/tests/StarWars/Schema/EpisodeEnum.php b/tests/StarWars/Schema/EpisodeEnum.php index 2c4c4436..14ff5862 100644 --- a/tests/StarWars/Schema/EpisodeEnum.php +++ b/tests/StarWars/Schema/EpisodeEnum.php @@ -13,7 +13,7 @@ class EpisodeEnum extends AbstractEnumType { - public function getValues() + public function getValues(): array { return [ [ @@ -37,7 +37,7 @@ public function getValues() /** * @return String type name */ - public function getName() + public function getName(): string { return 'Episode'; } diff --git a/tests/StarWars/Schema/HumanType.php b/tests/StarWars/Schema/HumanType.php index 8d02d346..a0fa6417 100644 --- a/tests/StarWars/Schema/HumanType.php +++ b/tests/StarWars/Schema/HumanType.php @@ -8,6 +8,7 @@ namespace Youshido\Tests\StarWars\Schema; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; use Youshido\GraphQL\Type\ListType\ListType; use Youshido\GraphQL\Type\NonNullType; use Youshido\GraphQL\Type\Object\AbstractObjectType; @@ -18,14 +19,14 @@ class HumanType extends AbstractObjectType { - public function build($config) + public function build(ObjectTypeConfig $config): void { $config ->addField('id', new NonNullType(new IdType())) ->addField('name', new NonNullType(new StringType())) ->addField('friends', [ 'type' => new ListType(new CharacterInterface()), - 'resolve' => function ($droid) { + 'resolve' => static function ($droid) { return StarWarsData::getFriends($droid); }, ]) diff --git a/tests/StarWars/Schema/StarWarsData.php b/tests/StarWars/Schema/StarWarsData.php index d2d28607..2ced5280 100644 --- a/tests/StarWars/Schema/StarWarsData.php +++ b/tests/StarWars/Schema/StarWarsData.php @@ -10,7 +10,7 @@ class StarWarsData { - private static function luke() + private static function luke(): array { return [ 'id' => '1000', @@ -21,7 +21,7 @@ private static function luke() ]; } - private static function vader() + private static function vader(): array { return [ 'id' => '1001', @@ -32,7 +32,7 @@ private static function vader() ]; } - private static function han() + private static function han(): array { return [ 'id' => '1002', @@ -42,7 +42,7 @@ private static function han() ]; } - private static function leia() + private static function leia(): array { return [ 'id' => '1003', @@ -53,7 +53,7 @@ private static function leia() ]; } - private static function tarkin() + private static function tarkin(): array { return [ 'id' => '1004', @@ -63,7 +63,7 @@ private static function tarkin() ]; } - static function humans() + public static function humans(): array { return [ '1000' => self::luke(), @@ -74,7 +74,7 @@ static function humans() ]; } - private static function threepio() + private static function threepio(): array { return [ 'id' => '2000', @@ -89,7 +89,7 @@ private static function threepio() * We export artoo directly because the schema returns him * from a root field, and hence needs to reference him. */ - static function artoo() + public static function artoo(): array { return [ @@ -101,7 +101,7 @@ static function artoo() ]; } - static function droids() + public static function droids(): array { return [ '2000' => self::threepio(), @@ -112,13 +112,14 @@ static function droids() /** * Helper function to get a character by ID. */ - static function getCharacter($id) + public static function getCharacter($id) { $humans = self::humans(); $droids = self::droids(); if (isset($humans[$id])) { return $humans[$id]; } + if (isset($droids[$id])) { return $droids[$id]; } @@ -130,7 +131,7 @@ static function getCharacter($id) * @param $episode * @return array */ - static function getHero($episode) + public static function getHero($episode) { if ($episode === 5) { // Luke is the hero of Episode V. @@ -144,7 +145,7 @@ static function getHero($episode) /** * Allows us to query for a character's friends. */ - static function getFriends($character) + public static function getFriends(array $character): array { return array_map([__CLASS__, 'getCharacter'], $character['friends']); } diff --git a/tests/StarWars/Schema/StarWarsQueryType.php b/tests/StarWars/Schema/StarWarsQueryType.php index e54f072d..eff36246 100644 --- a/tests/StarWars/Schema/StarWarsQueryType.php +++ b/tests/StarWars/Schema/StarWarsQueryType.php @@ -8,8 +8,9 @@ namespace Youshido\Tests\StarWars\Schema; +use Youshido\GraphQL\Config\Object\ObjectTypeConfig; +use Youshido\GraphQL\Exception\ConfigurationException; use Youshido\GraphQL\Field\Field; -use Youshido\GraphQL\Field\FieldFactory; use Youshido\GraphQL\Type\Object\AbstractObjectType; use Youshido\GraphQL\Type\Scalar\IdType; @@ -19,12 +20,15 @@ class StarWarsQueryType extends AbstractObjectType /** * @return String type name */ - public function getName() + public function getName(): string { return 'Query'; } - public function build($config) + /** + * @throws ConfigurationException + */ + public function build(ObjectTypeConfig $config): void { $config ->addField('hero', [ @@ -32,8 +36,8 @@ public function build($config) 'args' => [ 'episode' => ['type' => new EpisodeEnum()] ], - 'resolve' => function ($root, $args) { - return StarWarsData::getHero(isset($args['episode']) ? $args['episode'] : null); + 'resolve' => static function ($root, array $args) { + return StarWarsData::getHero($args['episode'] ?? null); }, ]) ->addField(new Field([ @@ -42,10 +46,9 @@ public function build($config) 'args' => [ 'id' => new IdType() ], - 'resolve' => function ($value = null, $args = []) { + 'resolve' => static function ($value = null, array $args = []) { $humans = StarWarsData::humans(); - - return isset($humans[$args['id']]) ? $humans[$args['id']] : null; + return $humans[$args['id']] ?? null; } ])) ->addField(new Field([ @@ -54,10 +57,9 @@ public function build($config) 'args' => [ 'id' => new IdType() ], - 'resolve' => function ($value = null, $args = []) { + 'resolve' => static function ($value = null, array $args = []) { $droids = StarWarsData::droids(); - - return isset($droids[$args['id']]) ? $droids[$args['id']] : null; + return $droids[$args['id']] ?? null; } ])); } diff --git a/tests/StarWars/Schema/StarWarsSchema.php b/tests/StarWars/Schema/StarWarsSchema.php index 1ed58262..2a72ad3d 100644 --- a/tests/StarWars/Schema/StarWarsSchema.php +++ b/tests/StarWars/Schema/StarWarsSchema.php @@ -14,7 +14,7 @@ class StarWarsSchema extends AbstractSchema { - public function build(SchemaConfig $config) + public function build(SchemaConfig $config): void { $config->setQuery(new StarWarsQueryType()); } diff --git a/tests/StarWars/StarWarsTest.php b/tests/StarWars/StarWarsTest.php index 7f69a4b2..01874035 100644 --- a/tests/StarWars/StarWarsTest.php +++ b/tests/StarWars/StarWarsTest.php @@ -21,7 +21,7 @@ class StarWarsTest extends \PHPUnit_Framework_TestCase * * @dataProvider dataProvider */ - public function testSchema($query, $validResult, $variables) + public function testSchema($query, $validResult, $variables): void { $processor = new Processor(new StarWarsSchema()); @@ -31,7 +31,7 @@ public function testSchema($query, $validResult, $variables) $this->assertEquals($validResult, $responseData); } - public function testInvalidVariableType() + public function testInvalidVariableType(): void { $processor = new Processor(new StarWarsSchema());