magdv/yii2-graphql

为yii2 PHP框架提供的GraphQL服务器端实现

维护者

详细信息

github.com/magdv/yii2-graphql

源代码

安装: 362

依赖者: 0

建议者: 0

安全: 0

星标: 0

关注者: 0

分支: 26

类型:yii2-extension

0.0.2 2024-04-18 09:02 UTC

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

  1. 在你的基础路径(即backend)中创建一个名为modules的文件夹

  2. 在模块文件夹中创建一个名为graphql的文件夹。因此backend/modules/graphql

  3. 在那里创建一个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;
 }
  1. backend/config/main.php中找到modules配置并将其添加到其中,使其看起来像这样
'modules' => [
    'graphql => [
        'class' => 'backend\modules\graphql\GraphqlModule',
    ]
]

创建一个Controller

  1. 在你的modules/graphql文件夹中创建一个名为controllers的文件夹。
  2. 在那里创建一个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一样

  1. 在你的模块中创建一个名为types的文件夹。
  2. 创建一个名为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查询

  1. 在你的模块中创建一个名为queries的文件夹。
  2. 创建一个名为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

  1. 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
    ]
];
  1. backend/config/main.phpmodules部分中添加到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属性中,或作为方法,除非另有说明。这也适用于此之后的所有元素。

查询

GraphQLQueryGraphQLMutation继承自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

授权

如果用户已经通过认证,你可能想检查对资源的访问权限。你可以在控制器中使用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');
        }
    }
}