magdv / yii2-graphql
为yii2 PHP框架提供的GraphQL服务器端实现
Requires
- php: ^8.0
- ecodev/graphql-upload: ^6.1
- laminas/laminas-diactoros: ^3.2
- webonyx/graphql-php: ^14.11
- yiisoft/yii2: ^2.0.47
Requires (Dev)
- overtrue/phplint: ^9.0
- phpunit/phpunit: ^9
- rector/rector: ^1.0
- squizlabs/php_codesniffer: ^3.9
- vimeo/psalm: 5.23.1
This package is auto-updated.
Last update: 2024-09-18 09:55:50 UTC
README
使用GraphQL PHP服务器端实现。它是yii2-graphql的一个分支,将graphql-php扩展到适用于Yii2。
指南(适用于Yii基本模板)
与Yii高级模板相同,但
- 而不是
backend
命名空间,是app
- 例如,命名空间应该是
namespace app\modules\graphql\...
- 例如,命名空间应该是
- 而不是
main.php
,是web.php
例如:- 例如,配置在
config/web.php
- 例如,配置在
指南(适用于Yii高级模板)
安装
使用composer
composer require Plato-solutions/yii2-graphql
启用Yii JsonParser
要在backend/config/main.php
中启用对JSON请求的解析
'components' => [ 'request' => [ // ... other config 'parsers' => [ 'application/json' => 'yii\web\JsonParser', ] ] ]
创建一个GraphQLModule
-
在你的基础路径(即
backend
)中创建一个名为modules
的文件夹 -
在模块文件夹中创建一个名为
graphql
的文件夹。因此backend/modules/graphql
-
在那里创建一个
GraphqlModule.php
文件,内容如下:backend/modules/graphql/GraphqlModule.php
<?php namespace backend\modules\graphql; use yii\base\Module; use yii\graphql\GraphQLModuleTrait; class GraphqlModule extends Module{ use GraphQLModuleTrait; }
- 在
backend/config/main.php
中找到modules
配置并将其添加到其中,使其看起来像这样
'modules' => [ 'graphql => [ 'class' => 'backend\modules\graphql\GraphqlModule', ] ]
创建一个Controller
- 在你的
modules/graphql
文件夹中创建一个名为controllers
的文件夹。 - 在那里创建一个
DefaultController.php
文件,内容如下
<?php namespace backend\modules\graphql\controllers; use Yii; use yii\rest\Controller; class DefaultController extends Controller { public function actions() { Yii::$app->response->format = \yii\web\Response::FORMAT_JSON; return [ 'index' => [ 'class' => 'yii\graphql\GraphQLAction' ], ]; } }
创建GraphQL类型
对于在backend/models
文件夹中的模型,例如以下示例,
<?php /** * This is the model class for table "country". * * @property string $code * @property string $name * @property int $population * @property Person $leader */ class Country extends \yii\db\ActiveRecord {
其中Person是另一个模型,具有自己的属性,就像Country
一样
- 在你的模块中创建一个名为
types
的文件夹。 - 创建一个名为
CountryType.php
(使用模型类名命名,后缀为Type)的内容如下
<?php namespace backend\modules\graphql\types; use GraphQL\Type\Definition\Type; use yii\graphql\base\GraphQLType; use yii\graphql\GraphQL; class CountryType extends GraphQLType { protected $attributes = [ 'name' => 'country', 'description' => 'description here' ]; public function fields() { return [ 'id' => Type::id(), 'name' => Type::string(), 'population' => Type::int(), 'leader' => GraphQLType::type(PersonType::class) ]; } }
对backend\models
中的所有模型执行上述操作。
有关类型列表的完整列表,请参阅下方的标量类型。
为模型创建GraphQL查询
- 在你的模块中创建一个名为
queries
的文件夹。 - 创建一个名为
CountryQuery.php
(使用模型类名命名,后缀为Query)的内容如下
<?php namespace backend\modules\graphql\queries; use GraphQL\Type\Definition\Type; use yii\graphql\queries\ModelQuery; use backend\modules\graphql\types\CountryType; use backend\models\Country; class CountryQuery extends ModelQuery { public $type = CountryType::class; public $model = Country::class; public function args() { return [ 'id' => Type::id(), 'name' => Type::string(), 'population' => Type::int(), 'leaderId' => Type::id() ]; // replace the non-scalar type with it's id in the args } }
对backend\models
中你想要查询的所有模型执行上述操作。
设置Schema
- 在
backend/modules/graphql/
中创建一个名为schema.php
的PHP文件,内容如下
<?php return [ 'query' => [ 'country' => 'backend\modules\graphql\queries\CountryQuery', //... add all your queries here ], 'mutation' => [ //... add all your mutations here ], 'types' => [ 'country' => 'backend\modules\graphql\types\CountryType', //... add all your types here ] ];
- 在
backend/config/main.php
的modules
部分中添加到schema.php
的路径,如下所示(确保schema
的目录路径正确)。
'modules' => [ 'graphql' => [ 'class' => 'backend\modules\graphql\GraphqlModule', 'schema' => require __DIR__ . '/../../backend/modules/graphql/schema.php', ] ],
文档
类型
类型系统是GraphQL的核心,体现在GraphQLType
中。通过解构GraphQL协议和使用graph-php
库(graph-php),可以实现对所有元素的精细控制,便于根据自身需求扩展类。
标量类型
GraphQL规范描述了几个内置的标量类型。在graphql-php中,它们作为类GraphQL\Type\Definition\Type的静态方法暴露。
GraphQLType
的主要元素
以下元素可以声明在类的$attributes
属性中,或作为方法,除非另有说明。这也适用于此之后的所有元素。
查询
GraphQLQuery
和GraphQLMutation
继承自GraphQLField
。元素结构一致,如果你需要一个可重用的Field
,你可以继承它。每个Graphql
查询都需要对应一个GraphQLQuery
对象。ModelQuery
继承自GraphQLQuery
。
GraphQLField
的主要元素
突变
定义类似于GraphQLQuery
,请参考上文。
简化字段定义
简化了Field
的声明,无需将其定义为带有类型键的数组。
标准定义
//... 'id' => [ 'type' => Type::id(), ], //...
简化定义
//... 'id' => Type::id(), //...
输入验证
支持验证规则。除了基于GraphQL的验证外,还可以使用Yii Model验证,目前用于验证输入参数。规则方法直接添加到突变定义中。
public function rules() { return [ ['password','boolean'] ]; }
授权验证
由于GraphQL查询可以组合,例如当一个查询合并了两个查询,而这两个查询有不同的授权约束时,需要自定义授权。我称此查询为“graphql动作”;当所有graphql动作条件配置完成后,通过授权检查。
认证
在控制器行为方法中,将授权方法设置为以下内容
function behaviors() { return [ 'authenticator'=>[ 'class' => 'yii\graphql\filter\auth\CompositeAuth', 'authMethods' => [ \yii\filters\auth\QueryParamAuth::class, ], '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'); } } }