almservices / attributed-graphql-model-types
基于属性的 GraphQL 模型/类型
1.1.1
2022-08-03 19:18 UTC
Requires
- php: ^7.4 || ^8.0
- ext-mbstring: *
- nette/php-generator: ^3.6.6
- webonyx/graphql-php: ^v14.0.0
Requires (Dev)
- ext-dom: *
- doctrine/annotations: ^1.13
- doctrine/common: ^3.2
- phpstan/phpstan: ^1.4
- phpstan/phpstan-phpunit: ^1.0
- phpunit/phpunit: >=9
- symfony/polyfill-php80: ^1.25
This package is not auto-updated.
Last update: 2024-09-12 05:47:33 UTC
README
要求
- Composer
- PHP >=7.4
安装
composer require almservices/attributed-graphql-model-types
使用方法
假设我们有这样的模型
#[Model(name: "AnimalAlias")] class Animal { #[ID] #[Field] public int $id; #[Field] public string $name; }
或者使用 php7.4
/** * @Model(name: "AnimalAlias") */ class Animal { /** * @ID * @Field */ public int $id; /** * @Field */ public string $name; }
我们可以通过以下方式创建 GraphQL 类型
class AnimalType extends ModelType { public function __construct(bool $isProd) { parent::__construct(Animal::class, new TypeContainer($isProd), $isProd); } }
或者直接通过
new ModelType(Animal::class, new TypeContainer($isProd), $isProd);
这将等同于
class AnimalType extends \GraphQL\Type\Definition\ObjectType { public function __construct() { parent::__construct([ 'name' => 'AnimalAlias', 'fields' => static fn () => [ 'id' => [ 'resolve' => static fn (Animal $animal) => $animal->id, 'type' => self::nonNull(self::id()), ], 'name' => [ 'resolve' => static fn (Animal $animal) => $animal->name, 'type' => self::nonNull(self::string()), ], ], ]); } }
模型示例
字段
#[Model(name: "Foo")] class Foo { #[Field] public int $bar; #[Field] public function baz(): string { return 'baz'; } }
别名
#[Model(name: "AnimalAlias")] class Foo { #[Alias("bar")] #[Field] public int $foo; }
枚举
PHP 8.1
#[Model(name: "Family")] enum Family { case SEAL; case BEAR; }
PHP < 8.1 的内联版本
#[Model(name: "Foo")] class InlineEnum { #[Field] #[Enum("SingleEnum", "A", "B", "C", "D")] public string $single; #[Field] #[ListOf("ListEnum")] #[Enum("ListEnum", "A", "B", "C", "D")] public array $list; }
其他选项包括
#[Model("SomeEnum")] class SomeEnum: string { case FOO = 'foo'; // FOO }
#[Model("SomeEnum")] class SomeEnum: int { case FOO = 1; // FOO }
#[Model("SomeEnum")] class SomeEnum: string { #[Alias("foo")] case FOO = "bar"; // foo }
#[Model("SomeEnum")] class SomeEnum: int { #[Alias("foo")] case FOO = 1; // foo }
忽略特定字段
#[Model("SomeEnum")] class SomeEnum: int { case FOO; case BAR; #[Ignore] case BAZ; }
列表
#[Model("Foo")] class Foo { #[Field] #[ListOf(type: "string")] public \Traversable $test; // [String]! #[Field] #[ListOf(type: "string")] public array $foo; // [String]! #[Field] #[ListOf(type: self::class)] public iterable $bar; // [Foo]! #[Field] #[ListOf(type: OtherModel::class)] public array $baz; // [OtherModel]! #[Field] #[ListOf(type: OtherModel::class)] public \Doctrine\Common\Collections\Collection $qux; // [OtherModel]! }
对于非空项使用 NonNull
#[Model("Foo")] class Foo { #[Field] #[NonNull] #[ListOf("string")] public array $list; // [String!]! }
值对象
可以转换为字符串的旧版或自定义值对象,可以用作模型属性
class FooBar implements Stringable { private string $type; private function __construct(string $type) { $this->type = $type; } public static function foo(): self { return new self('foo'); } public static function bar(): self { return new self('foo'); } public function __toString(): string { return $this->type; } }
示例
#[Model(name: "Foo")] class Foo { #[ID] #[Field] public readonly FooBar $id; }
但如果值更复杂,它可以在需要时解决
#[Model(name: "Foo")] class Foo { public function __construct( private string $foo, private string $bar, ) {} #[ID] #[Field] public function id(): string { return $this->foo . $this->bar; } }
已弃用
#[Model(name: "Foo")] class Foo { #[Field] #[Deprecated("Do not use Foo.foo, use Foo.bar instead")] public function foo(): string { return 'foo'; } #[Field] public function bar(): string { return 'bar'; } }
描述
#[Description("Foo is Bar")] #[Model(name: "Foo")] class Foo { #[Field] #[Description("Foo foo?")] public function foo(): string { return 'foo'; } }
更多关于解析器的信息
#[Model("Foo")] class Foo { #[Field] #[Argument(name: "bar", type: "string", nullable: false)] #[Argument(name: "baz", type: "[String!]!")] #[Argument(name: "qux", type: "[string]", nullable: false)] public function bar( #[ArrayShape([ "baz" => "string[]" ])] array $args ): string { return implode(", ", $args['baz']); } }
带有目标输入类型的示例
class MyInput extends InputObjectType { public function __construct() { parent::__construct("MyInput", $this->fields()); } /** * @return \Generator<FieldInterface> */ private function fields(): \Generator { yield new Field("foo", Type::nonNull(Type::string())); } } // we need to register MyInput into map $typeContainer = new TypeContainer(); $typeContainer->set(MyInput::class, new MyInput()); $typeContainer->set("MyInput", new MyInput()); #[Model("Foo")] class Foo { #[Field] #[Argument(name: "baz", type: MyInput::class, nullable: false)] public function bar( #[ArrayShape([ "baz" => [ "foo" => "string" ] ])] array $args ): string { return $args['baz']['foo']; } }
完全合格解析器的示例
#[Model("Foo")] class Foo { #[Field] public function bar( #[ArrayShape([])] array $args, Context $context, ResolveInfo $resolveInfo ): string { return ''; } }
演示
要运行演示,请执行
php -S 127.0.0.1:8000 demo/index.php
curl 127.0.0.1:8000 -d '{"query": "{myUser{id firstName lastName}}"}' -H "Content-Type: application/json" -H 'Authorization: dev'