翻译进度
6
分块数量
3
参与人数

Interfaces

这是一篇社区协同翻译的文章,你可以点击右边区块信息里的『改进』按钮向译者提交改进建议。

定义接口类型

接口是一种抽象类型,它包含一类必须包含的用于实现接口的一组字段。

graphql-php 接口类型中是一个 GraphQL\Type\Definition\InterfaceType
(或其中一个子类)的实例,它接受构造函数中的配置数组:

<?php
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\Type;

$character = new InterfaceType([
    'name' => 'Character',
    'description' => 'A character in the Star Wars Trilogy',
    'fields' => [
        'id' => [
            'type' => Type::nonNull(Type::string()),
            'description' => 'The id of the character.',
        ],
        'name' => [
            'type' => Type::string(),
            'description' => 'The name of the character.'
        ]
    ],
    'resolveType' => function ($value) {
        if ($value->type === 'human') {
            return MyTypes::human();            
        } else {
            return MyTypes::droid();
        }
    }
]);

本示例使用 内联 样式来定义接口,但你也可以使用 继承或类型语言

Ellison 翻译于 3周前

配置选项

InterfaceType 的构造函数接受一个数组。以下是允许的选项的完整列表:

选项 类型 说明
name string 必需。 Schema 中该接口类型的唯一名称
fields array 必需。 接口实现者需要定义的字段列表。与 对象类型的字段 相同
description string 用于客户端的此类型的明文描述(例如,GraphiQL 用于自动生成的文档)
resolveType callback function($value, $context, ResolveInfo $info)
从父字段的解析器接收 $value,并返回 $value 的具体接口实现者。
Ellison 翻译于 3周前

实现 interface

要实现该接口,只需将其添加到对象类型定义的 接口 数组中即可:

<?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;

$humanType = new ObjectType([
    'name' => 'Human',
    'fields' => [
        'id' => [
            'type' => Type::nonNull(Type::string()),
            'description' => 'The id of the character.',
        ],
        'name' => [
            'type' => Type::string(),
            'description' => 'The name of the character.'
        ]
    ],
    'interfaces' => [
        $character
    ]
]);

请注意,对象类型必须包含完全相同类型(包括 非空 指定)和参数的所有接口字段。

唯一的例外是对象的字段类型比接口中定义的该字段的类型更具体(请参阅下面的 接口字段的Covariant返回类型 )。

接口字段的协变返回类型

实现接口的对象类型可能会将字段类型更改得更具体。

例如:

interface A {
  field1: A
}

type B implements A {
  field1: B
}
Ellison 翻译于 3周前

共享接口字段

因为每个实现了接口的对象类型必须都具有相同的字段集合,所以复用对象类型中的接口字段定义合情合理。

<?php
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\ObjectType;

$humanType = new ObjectType([
    'name' => 'Human',
    'interfaces' => [
        $character
    ],
    'fields' => [
        'height' => Type::float(),
        $character->getField('id'),
        $character->getField('name')
    ] 
]);
wilson_yang 翻译于 3周前

在这个例子中,字段定义只被创建了一次(作为一个接口类型),接下来就可以被所有的接口实现者复用。它可以节省几微秒和数千字节,同时确保接口和实现者的字段定义始终一致。

但是这也带来了字段解析问题。有两种方案可以解决这个问题:

  1. 如果字段解析算法在所有的接口实现者中都是一样的 - 可以简单添加
    resolve 选项到接口本身的字段定义中。

  2. 如果字段解析在各个实现中各不相同- 可以在 对象类型配置 中定义 resolveField 选项,然后在那里处理字段解析(注意:resolve 选项在对象类型定义中的优先级高于 resolveField 选项)。
wilson_yang 翻译于 3周前

数据获取中的接口角色

数据获取过程中的接口唯一职责就是返回 resolveType 中给定的 $value 的具体对象类型。然后将字段解析委派给此对象类型的解析器来处理。

如果 resolveType 选项被省略,graphql-php 将遍历所有的接口实现者然后使用它们的 isTypeOf 回调方法来选择第一个最适合的。 因此这明显比单独调用 resolveType 低效。所以建议尽量定义 resolveType

wilson_yang 翻译于 3周前

本文章首发在 Laravel China 社区
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

参与译者:3
讨论数量: 0
发起讨论


暂无话题~