tsingsun / yii2-graphql
Facebook GraphQL 服务器端,适用于 yii2 PHP 框架
Requires
- php: >=5.6.0
- webonyx/graphql-php: ^0.11
- yiisoft/yii2: ~2.0.10
Requires (Dev)
- phpunit/phpunit: 4.8.*
This package is not auto-updated.
Last update: 2022-04-30 14:44:59 UTC
README
使用 Facebook GraphQL PHP 服务器实现。扩展 graphql-php 以适用于 YII2。
功能
- 配置包括简化标准 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 定义的传递的类型实例。 |
查询
GraphQLQuery
和 GraphQLMutation
继承自 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 是查询参数,$context 是 yii\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
授权
如果用户已通过认证,您可能想检查对资源的访问权限。您可以在控制器中使用 GraphqlAction
的 checkAccess
方法。它将检查所有 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
,尚未测试。