almservices/attributed-graphql-model-types

基于属性的 GraphQL 模型/类型

1.1.1 2022-08-03 19:18 UTC

This package is not auto-updated.

Last update: 2024-09-12 05:47:33 UTC


README

Latest stable version CI Status Coverage Status PHP version License

要求

  • 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'