graphql php

2025-12-07 0 434

GraphQl

这是基于JavaScript参考实现的GraphQL规范的PHP实现。

相关项目

  • DateTime标量
  • 继电器支持

要求

  • PHP版本> = 7.1
  • EXT-MBSTRING

目录

  • 安装
  • 例子
  • 创建模式
  • 执行
    • 查询
    • 解析器
      • N+1问题
    • 变量
    • 语境
  • 标量
    • 自定义标量
  • 高级用法
  • 一体化
    • 拉拉维尔

安装

运行以下命令通过Composer安装软件包:

composer require digiaonline/graphql

例子

这是一个简单的示例,该示例演示了如何从GraphQl架构文件中构建可执行模式,该文件包含以星球大战为主题的架构的架构定义语言(SDL)(有关架构定义本身,请参见下文)。在此示例中,我们使用该SDL来构建可执行模式,并使用它来查询英雄名称。该查询的结果是一个关联阵列,其结构类似于我们运行的查询。

 use Digia \\ GraphQL \\ Language \\ FileSourceBuilder ;
use function Digia \\ GraphQL \\ buildSchema ;
use function Digia \\ GraphQL \\ graphql ;

$ sourceBuilder = new FileSourceBuilder ( __DIR__ . \' /star-wars.graphqls \' );

$ schema = buildSchema ( $ sourceBuilder -> build (), [
    \' Query \' => [
        \' hero \' => function ( $ rootValue , $ arguments ) {
            return getHero ( $ arguments [ \' episode \' ] ?? null );
        },
    ],
]);

$ result = graphql ( $ schema , \'
query HeroNameQuery {
  hero {
    name
  }
} \' );

\\print_r ( $ result );

上面的脚本产生以下输出:

 Array
(
    [data] => Array
    (
        [hero] => Array
        (
            [name] => \" R2-D2 \"
        )
        
    )
    
)

此示例中使用的GraphQL架构文件包含以下内容:

 schema {
    query : Query
}

type Query {
    hero ( episode : Episode ): Character
    human ( id : String ! ): Human
    droid ( id : String ! ): Droid
}

interface Character {
    id : String !
    name : String
    friends : [ Character ]
    appearsIn : [ Episode ]
}

type Human implements Character {
    id : String !
    name : String
    friends : [ Character ]
    appearsIn : [ Episode ]
    homePlanet : String
}

type Droid implements Character {
    id : String !
    name : String
    friends : [ Character ]
    appearsIn : [ Episode ]
    primaryFunction : String
}

enum Episode { NEWHOPE , EMPIRE , JEDI }

创建模式

为了针对您的GraphQl API执行查询,您首先需要定义API的结构。这是通过创建模式来完成的。有两种方法可以这样做,您可以使用SDL进行操作,也可以通过编程方式进行操作。但是,我们强烈建议您使用SDL,因为它更容易使用。要从SDL制作可执行模式,您需要调用buildSchema函数。

buildSchema函数需要三个参数:

  • $source架构定义(SDL)作为Source实例
  • $resolverRegistry一个关联阵列或包含所有解析器的ResolverRegistry实例
  • $options构建模式的选项,其中还包括自定义类型和指令

要创建Source实例,您可以使用提供的FileSourceBuilderMultiFileSourceBuilder类。

解析器注册表

解析器注册表本质上是一张平面地图,其类型名称为键及其相应的解析器实例作为其值。对于较小的项目,您可以使用关联数组和Lambda功能来定义您的解析器注册表。但是,在较大的项目中,我们建议您实施自己的解析器。您可以在“解析器”部分下阅读有关解析器的更多信息。

关联阵列示例:

 $ schema = buildSchema ( $ source , [
    \' Query \' => [
        \' hero \' => function ( $ rootValue , $ arguments ) {
            return getHero ( $ arguments [ \' episode \' ] ?? null );
        },
    ],
]);

解析器类示例:

 $ schema = buildSchema ( $ source , [
    \' Query \' => [
        \' hero \' => new HeroResolver (),
    ],
]);

解析器中间件

如果您发现自己在多个解析器中编写相同的逻辑,则应考虑使用中间件。解析器中间件允许您有效地管理多个解析器的功能。

中间件示例之前:

 $ resolverRegistry = new ResolverRegristry ([
    \' Query \' => [
        \' hero \' => function ( $ rootValue , $ arguments ) {
            return getHero ( $ arguments [ \' episode \' ] ?? null );
        },
    ],
], [
    \' middleware \' => [ new BeforeMiddleware ()],
]);
$ schema = buildSchema ( $ source , $ resolverRegistry );
 class BeforeMiddleware implements ResolverMiddlewareInterface
{
    public function resolve ( callable $ resolveCallback , $ rootValue , array $ arguments , $ context , ResolveInfo $ info ) {
        $ newRootValue = $ this -> doSomethingBefore ();
        return $ resolveCallback ( $ newRootValue , $ arguments , $ context , $ info );
    }
}

中间件之后示例:

 $ resolverRegistry = new ResolverRegristry ([
    \' Query \' => [
        \' hero \' => function ( $ rootValue , $ arguments ) {
            return getHero ( $ arguments [ \' episode \' ] ?? null );
        },
    ],
], [
    \' middleware \' => [ new AfterMiddleware ()],
]);
$ schema = buildSchema ( $ source , $ resolverRegistry );
 class AfterMiddleware implements ResolverMiddlewareInterface
{
    public function resolve ( callable $ resolveCallback , $ rootValue , array $ arguments , $ context , ResolveInfo $ info ) {
        $ result = $ resolveCallback ( $ rootValue , $ arguments , $ context , $ info );
        $ this -> doSomethingAfter ();
        return $ result ;
    }
}

解析器中间件对于许多事情都有用。例如记录,输入消毒,性能测量,授权和缓存。

如果您想了解有关模式的更多信息,则可以参考规范。

执行

查询

要执行针对您的架构的查询,您需要调用graphql函数并将其传递您的模式以及您希望执行的查询。您还可以通过更改查询来运行突变订阅

 $ query = \'
query HeroNameQuery {
  hero {
    name
  }
} \' ;

$ result = graphql ( $ schema , $ query );

如果您想了解有关查询的更多信息,则可以参考规范。

解析器

模式中的每种类型都有与之关联的解析器,可以解决实际值。但是,大多数类型不需要自定义解析器,因为它们可以使用默认的解析器解决。通常,这些解析器是lambda功能,但是您也可以通过扩展AbstractTypeResolverAbstractFieldResolver来定义自己的解析器。另外,您还可以直接实现ResolverInterface

解析器功能会收到四个参数:

  • $rootValue父对象,在某些情况下也可以null
  • $arguments查询中提供给字段的参数
  • $context一个传递给每个可以保存重要上下文信息的解析器的值
  • $info一个值,该值包含与当前查询相关的特定领域信息

lambda功能示例:

 function ( $ rootValue , array $ arguments , $ context , ResolveInfo $ info ): string {
    return [
        \' type \'       => \' Human \' ,
        \' id \'         => \' 1000 \' ,
        \' name \'       => \' Luke Skywalker \' ,
        \' friends \'    => [ \' 1002 \' , \' 1003 \' , \' 2000 \' , \' 2001 \' ],
        \' appearsIn \'  => [ \' NEWHOPE \' , \' EMPIRE \' , \' JEDI \' ],
        \' homePlanet \' => \' Tatooine \' ,
    ];
}

类型解析器示例:

 class HumanResolver extends AbstractTypeResolver
{
    public function resolveName ( $ rootValue , array $ arguments , $ context , ResolveInfo $ info ): string
    {
        return $ rootValue [ \' name \' ];
    }
}

现场解析器示例:

 class NameResolver extends AbstractFieldResolver
{
    public function resolve ( $ rootValue , array $ arguments , $ context , ResolveInfo $ info ): string
    {
       return $ rootValue [ \' name \' ];
    }
}

N+1问题

解析器功能可以返回值,承诺或一系列承诺。下面的该解析器功能说明了如何使用承诺解决N+1问题,可以在此测试案例中找到完整的示例。

 $ movieType = newObjectType ([
    \' fields \' => [
        \' title \'    => [ \' type \' => stringType ()],
        \' director \' => [
            \' type \'    => $ directorType ,
            \' resolve \' => function ( $ movie , $ args ) {
                DirectorBuffer:: add ( $ movie [ \' directorId \' ]);
                
                return new Promise ( function ( callable $ resolve , callable $ reject ) use ( $ movie ) {
                    DirectorBuffer:: loadBuffered ();
                    $ resolve (DirectorBuffer:: get ( $ movie [ \' directorId \' ]));
                });
            }
        ]
    ]
]);

变量

通过将查询传递到graphql函数时,您可以通过变量传递。

 $ query = \'
query HeroNameQuery($id: ID!) {
  hero(id: $id) {
    name
  }
} \' ;

$ variables = [ \' id \' => \' 1000 \' ];

$ result = graphql ( $ schema , $ query , null , null , $ variables );

语境

如果您需要将一些重要的上下文信息传递给查询,则可以使用graphql上的$contextValues参数进行此操作。这些数据将作为$context参数传递给所有解析器。

 $ contextValues = [
    \' currentlyLoggedInUser \' => $ currentlyLoggedInUser ,
];

$ result = graphql ( $ schema , $ query , null , $ contextValues , $ variables );

标量

架构中的叶节点称为标量,每个标量都分解为某些具体数据。 GraphQL中的内置或指定标量如下:

  • 布尔
  • 漂浮
  • int
  • ID
  • 细绳

自定义标量

除指定的标量外,您还可以定义自己的自定义标量,并通过将它们传递到buildSchema函数作为$options参数的一部分,让您的模式知道它们。

自定义日期标量类型示例:

 $ dateType = newScalarType ([
    \' name \'         => \' Date \' ,
    \' serialize \'    => function ( $ value ) {
        if ( $ value instanceof DateTime) {
            return $ value -> format ( \' Y-m-d \' );
        }
        return null ;
    },
    \' parseValue \'   => function ( $ value ) {
        if ( \\is_string ( $ value )){
            return new DateTime ( $ value );
        }
        return null ;
    },
    \' parseLiteral \' => function ( $ node ) {
        if ( $ node instanceof StringValueNode) {
            return new DateTime ( $ node -> getValue ());
        }
        return null ;
    },
]);

$ schema = buildSchema ( $ source , [
    \' Query \' => QueryResolver::class,
    [
        \' types \' => [ $ dateType ],
    ],
]);

每个标量都必须强制强制,这是由三个不同功能完成的。 serialize函数将PHP值转换为相应的输出值。 parseValue函数将变量输入值转换为相应的PHP值,而parseLiteral函数将AST字面函数转换为相应的PHP值。

高级用法

如果您正在寻找此文档尚未涵盖的内容,那么最好的选择就是看该项目中的测试。您会惊讶于您在那里找到多少个例子。

一体化

拉拉维尔

这是一个示例,演示了如何在Laravel项目中使用此库。您需要一个应用程序服务来将此库曝光到您的应用程序,一个服务提供商可以注册该服务,控制器和处理GraphQl Post请求的路由。

app/graphql/graphqlservice.php

 class GraphQLService
{
    private $ schema ;

    public function __construct ( Schema $ schema )
    {
        $ this -> schema = $ schema ;
    }

    public function executeQuery ( string $ query , array $ variables , ? string $ operationName ): array
    {
        return graphql ( $ this -> schema , $ query , null , null , $ variables , $ operationName );
    }
}

app/graphql/graphqlServiceProvider.php

 class GraphQLServiceProvider
{
    public function register ()
    {
        $ this -> app -> singleton (GraphQLService::class, function () {
            $ schemaDef = \\file_get_contents ( __DIR__ . \' /schema.graphqls \' );

            $ executableSchema = buildSchema ( $ schemaDef , [
                \' Query \' => QueryResolver::class,
            ]);

            return new GraphQLService ( $ executableSchema );
        });
    }
}

app/graphql/graphqlcontroller.php

 class GraphQLController extends Controller
{
    private $ graphqlService ;

    public function __construct ( GraphQLService $ graphqlService )
    {
        $ this -> graphqlService = $ graphqlService ;
    }

    public function handle ( Request $ request ): JsonResponse
    {
        $ query         = $ request -> get ( \' query \' );
        $ variables     = $ request -> get ( \' variables \' ) ?? [];
        $ operationName = $ request -> get ( \' operationName \' );

        $ result = $ this -> graphqlService -> executeQuery ( $ query , $ variables , $ operationName );

        return response ()-> json ( $ result );
    }
}

路由/api.php

Route:: post ( \' /graphql \' , \' app\\GraphQL\\GraphQLController@handle \' );

贡献者

由于所有贡献的人,该项目的存在。贡献。

支持者

感谢我们所有的支持者!成为支持者

赞助商

通过成为赞助商来支持这个项目。您的徽标将在此处显示您网站的链接。成为赞助商

执照

请参阅许可证。

下载源码

通过命令行克隆项目:

git clone https://github.com/digiaonline/graphql-php.git

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 开发教程 graphql php https://www.zuozi.net/31909.html

MinimalApi
下一篇: MinimalApi
常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务