tsingsun/yii2-graphql

此包已被废弃,不再维护。未建议替代包。

Facebook GraphQL 服务器端,适用于 yii2 PHP 框架

安装量: 13,510

依赖: 0

建议者: 0

安全性: 0

星标: 96

关注者: 11

分支: 21

开放问题: 7

类型:yii2-extension

0.11.4 2018-01-27 13:55 UTC

This package is not auto-updated.

Last update: 2022-04-30 14:44:59 UTC


README

使用 Facebook GraphQL PHP 服务器实现。扩展 graphql-php 以适用于 YII2。

Latest Stable Version Build Status Total Downloads

中文文档

功能

  • 配置包括简化标准 GraphQL 协议的定义。
  • 基于类型的全名,实现按需加载和懒加载,无需在加载时将所有类型定义放入系统中。
  • 支持突变输入验证。
  • 提供控制器集成和授权支持。

安装

使用 composer

composer require tsingsun/yii2-graphql

类型

类型系统是 GraphQL 的核心,体现在 GraphQLType 中。通过分解 GraphQL 协议并使用 graph-php 库来实现对所有元素的精细控制,方便根据自身需求扩展类。

GraphQLType 的主要元素

以下元素可以声明在类的 $attributes 属性中,或作为方法,除非另有说明。这也适用于此之后的所有元素。

元素 类型 描述
name string 必需 每个类型都需要命名,最好使用唯一名称以解决潜在的冲突。该属性需要在 $attributes 属性中定义。
description string 对类型及其使用的描述。该属性需要在 $attributes 属性中定义。
fields array 必需 包含的字段内容由 fields () 方法表示。
resolveField 回调 函数($value, $args, $context, GraphQL\Type\Definition\ResolveInfo $info) 用于解释字段。例如:用户属性的字段定义,相应的方法是 resolveUserField(),而 $value 是由 type 定义的传递的类型实例。

查询

GraphQLQueryGraphQLMutation 继承自 GraphQLField。元素结构一致,如果需要一个可重用的 Field,可以继承它。每个 Graphql 查询都需要对应一个 GraphQLQuery 对象

GraphQLField 的主要元素

元素 类型 描述
type ObjectType 对于相应的查询类型。单一类型由 GraphQL::type 指定,列表由 Type::listOf(GraphQL::type) 指定。
args array 可用的查询参数,每个参数都由 Field 定义。
resolve 回调 function($value, $args, $context, GraphQL\Type\Definition\ResolveInfo $info) $value 是根数据,$args 是查询参数,$contextyii\web\Application 对象,$info 解析查询的对象。根对象在此方法中处理。

变更

定义类似于 GraphQLQuery,请参考上面。

简化字段定义

简化了 Field 的声明,无需将其定义为具有类型键的数组。

标准定义

//...
'id' => [
    'type' => Type::id(),
],
//...

简化定义

//...
'id' => Type::id(),
//...

Yii 实现

通用配置

需要 JsonParser 配置

'components' => [
    'request' => [
        'parsers' => [
            'application/json' => 'yii\web\JsonParser',
        ],
    ],
];

模块支持

可以使用 yii\graphql\GraphQLModuleTrait 容易地实现。特质负责初始化。

class MyModule extends \yii\base\Module
{
    use \yii\graphql\GraphQLModuleTrait;
}

在您的应用程序配置文件中

'modules'=>[
    'moduleName ' => [
        'class' => 'path\to\module'
        //graphql config
        'schema' => [
            'query' => [
                'user' => 'app\graphql\query\UsersQuery'
            ],
            'mutation' => [
                'login'
            ],
            // you do not need to set the types if your query contains interfaces or fragments
            // the key must same as your defined class
            'types' => [
                'Story' => 'yiiunit\extensions\graphql\objects\types\StoryType'
            ],
        ],
    ],
];

使用控制器通过 yii\graphql\GraphQLAction 接收请求

class MyController extends Controller
{
   function actions() {
       return [
            'index'=>[
                'class'=>'yii\graphql\GraphQLAction'
            ],
       ];
   }
}

组件支持

您还可以将特质包含在您自己的组件中,然后自行初始化。

'components'=>[
    'componentsName' => [
        'class' => 'path\to\components'
        //graphql config
        'schema' => [
            'query' => [
                'user' => 'app\graphql\query\UsersQuery'
            ],
            'mutation' => [
                'login'
            ],
            // you do not need to set the types if your query contains interfaces or fragments
            // the key must same as your defined class
            'types'=>[
                'Story'=>'yiiunit\extensions\graphql\objects\types\StoryType'
            ],
        ],
    ],
];

输入验证

支持验证规则。除了基于 GraphQL 的验证外,您还可以使用 Yii 模型验证,目前它用于输入参数的验证。规则方法直接添加到变更定义中。

public function rules() {
    return [
        ['password','boolean']
    ];
}

授权验证

由于 GraphQL 查询可以组合,例如当查询合并两个查询,并且两个查询有不同的授权约束时,需要自定义认证。我将此查询称为“GraphQL 操作”;当所有 GraphQL 操作条件配置完成后,它将通过授权检查。

认证

在控制器的行为方法中,将授权方法设置如下

function behaviors() {
    return [
        'authenticator'=>[
            'class' => 'yii\graphql\filter\auth\CompositeAuth',
            'authMethods' => [
                \yii\filters\auth\QueryParamAuth::className(),
            ],
            'except' => ['hello']
        ],
    ];
}

如果您想支持 IntrospectionQuery 授权,相应的 GraphQL 操作是 __schema

授权

如果用户已通过认证,您可能想检查对资源的访问权限。您可以在控制器中使用 GraphqlActioncheckAccess 方法。它将检查所有 GraphQL 操作。

class GraphqlController extends Controller
{
    public function actions() {
        return [
            'index' => [
                'class' => 'yii\graphql\GraphQLAction',
                'checkAccess'=> [$this,'checkAccess'],
            ]
        ];
    }

    /**
     * authorization
     * @param $actionName
     * @throws yii\web\ForbiddenHttpException
     */
    public function checkAccess($actionName) {
        $permissionName = $this->module->id . '/' . $actionName;
        $pass = Yii::$app->getAuthManager()->checkAccess(Yii::$app->user->id,$permissionName);
        if (!$pass){
            throw new yii\web\ForbiddenHttpException('Access Denied');
        }
    }
}

演示

根据 GraphQL 协议创建查询

每个查询对应一个 GraphQLQuery 文件。

class UserQuery extends GraphQLQuery
{
    public function type() {
        return GraphQL::type(UserType::class);
    }

    public function args() {
        return [
            'id'=>[
                'type' => Type::nonNull(Type::id())
            ],
        ];
    }

    public function resolve($value, $args, $context, ResolveInfo $info) {
        return DataSource::findUser($args['id']);
    }


}

根据查询协议定义类型文件

class UserType extends GraphQLType
{
    protected $attributes = [
        'name'=>'user',
        'description'=>'user is user'
    ];

    public function fields()
    {
        $result = [
            'id' => ['type'=>Type::id()],
            'email' => Types::email(),
            'email2' => Types::email(),
            'photo' => [
                'type' => GraphQL::type(ImageType::class),
                'description' => 'User photo URL',
                'args' => [
                    'size' => Type::nonNull(GraphQL::type(ImageSizeEnumType::class)),
                ]
            ],
            'firstName' => [
                'type' => Type::string(),
            ],
            'lastName' => [
                'type' => Type::string(),
            ],
            'lastStoryPosted' => GraphQL::type(StoryType::class),
            'fieldWithError' => [
                'type' => Type::string(),
                'resolve' => function() {
                    throw new \Exception("This is error field");
                }
            ]
        ];
        return $result;
    }

    public function resolvePhotoField(User $user,$args){
        return DataSource::getUserPhoto($user->id, $args['size']);
    }

    public function resolveIdField(User $user, $args)
    {
        return $user->id.'test';
    }

    public function resolveEmail2Field(User $user, $args)
    {
        return $user->email2.'test';
    }


}

查询实例

'hello' =>  "
        query hello{hello}
    ",

    'singleObject' =>  "
        query user {
            user(id:\"2\") {
                id
                email
                email2
                photo(size:ICON){
                    id
                    url
                }
                firstName
                lastName

            }
        }
    ",
    'multiObject' =>  "
        query multiObject {
            user(id: \"2\") {
                id
                email
                photo(size:ICON){
                    id
                    url
                }
            }
            stories(after: \"1\") {
                id
                author{
                    id
                }
                body
            }
        }
    ",
    'updateObject' =>  "
        mutation updateUserPwd{
            updateUserPwd(id: \"1001\", password: \"123456\") {
                id,
                username
            }
        }
    "

异常处理

您可以为图形配置错误格式化器。默认处理程序使用 yii\graphql\ErrorFormatter,该处理程序优化了模型验证结果的处理。

'modules'=>[
    'moduleName' => [
       'class' => 'path\to\module'
       'errorFormatter' => ['yii\graphql\ErrorFormatter', 'formatError'],
    ],
];

未来

  • ActiveRecord 工具用于生成查询和突变类。
  • 一些 GraphQL 的特殊语法,如 @Directives,尚未测试。