wucdbm / gmostafa-php-graphql-client
GraphQL 客户端和查询构建器。
Requires
- php: ^8.0
- ext-json: *
- guzzlehttp/guzzle: ^6.3|^7.0.1
- psr/http-client: ^1.0
- psr/http-message: ^1.0
Requires (Dev)
- aws/aws-sdk-php: ^3.186
- codacy/coverage: ^1.4
- phpunit/phpunit: ^7.5|^8.0|^9.0
Suggests
- aws/aws-sdk-php: Move this package to require section to use AWS IAM authorization
- gmostafa/php-graphql-oqm: To have object-to-query mapping support
Conflicts
- guzzlehttp/psr7: < 1.7.0
- dev-master
- v2.0.x-dev
- v1.14.2
- v1.14.1
- v1.14.0
- v1.13
- v1.12
- v1.11
- v1.10
- v1.9.2
- v1.9.1
- v1.9
- v1.8
- v1.7
- v1.6.1
- v1.6
- v1.5
- v1.4.1
- v1.4
- v1.3.1
- v1.3
- v1.2
- v1.1.1
- v1.1
- v1.0
- v0.6
- v0.5
- v0.4
- v0.3.5
- v0.3.4
- v0.3.3
- v0.3.2
- v0.3.1
- v0.3
- v0.2
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1
- dev-mghoneimy-github-actions
- dev-laravel8
- dev-feature/GQL-31
- dev-php5.6
- dev-hotfix/GQL-18
This package is auto-updated.
Last update: 2024-09-10 23:56:12 UTC
README
一个用 PHP 编写的 GraphQL 客户端,它提供了非常简单、功能强大的查询生成类,使得与 GraphQL 服务器交互变得非常简单。
用法
有三种主要方式使用此包来生成您的 GraphQL 查询
- 查询类:简单类,映射到 GraphQL 查询。它旨在轻松快速地操作查询。
- QueryBuilder 类:可以用来动态生成
Query
对象的构建器类。它设计用于在动态构建查询的情况下使用。 - PHP GraphQL-OQM:此包的扩展。它消除了编写任何 GraphQL 查询或参考 API 文档或语法的需要。它从 API 模式生成查询对象,通过 GraphQL 的内省公开声明,然后可以简单地与之交互。
安装
运行以下命令使用 composer 安装此包
$ composer require gmostafa/php-graphql-client
对象到查询映射扩展
为了避免编写 任何 查询并仅与从您的 API 模式生成的 PHP 对象交互的麻烦,请访问 PHP GraphQL OQM 存储库
查询示例
简单查询
$gql = (new Query('companies')) ->setSelectionSet( [ 'name', 'serialNumber' ] );
此简单查询将检索显示名称和序列号的全部公司。
完整形式
在上一个示例中提供的查询表示为“缩写形式”。缩写形式涉及编写较少的代码行,这加快了编写查询的过程。下面是上一个示例中相同查询的完整形式示例。
$gql = (new Query()) ->setSelectionSet( [ (new Query('companies')) ->setSelectionSet( [ 'name', 'serialNumber' ] ) ] );
如示例所示,缩写形式更容易阅读和编写,通常比完整形式更受欢迎。
除非查询无法用缩写形式表示,否则不应使用完整形式,这只有一个情况,即我们想在同一个对象中运行多个查询。
多个查询
$gql = (new Query()) ->setSelectionSet( [ (new Query('companies')) ->setSelectionSet( [ 'name', 'serialNumber' ] ), (new Query('countries')) ->setSelectionSet( [ 'name', 'code', ] ) ] );
此查询检索所有公司和国家,并显示每个的一些数据字段。它基本上在一个查询对象包装中运行两个(或更多)独立的查询。
编写多个查询需要以完整形式编写查询对象,以将每个查询作为父查询对象的子字段表示。
嵌套查询
$gql = (new Query('companies')) ->setSelectionSet( [ 'name', 'serialNumber', (new Query('branches')) ->setSelectionSet( [ 'address', (new Query('contracts')) ->setSelectionSet(['date']) ] ) ] );
此查询是一个更复杂的查询,不仅检索标量字段,还检索对象字段。此查询返回所有公司,显示其名称、序列号,并为每个公司,显示其所有分支、分支地址,并为每个地址,检索绑定到此地址的所有合同、显示其日期。
带参数的查询
$gql = (new Query('companies')) ->setArguments(['name' => 'Tech Co.', 'first' => 3]) ->setSelectionSet( [ 'name', 'serialNumber' ] );
此查询不是通过添加参数检索所有公司。此查询将检索名称为“Tech Co.”的前 3 家公司,显示其名称和序列号。
带数组参数的查询
$gql = (new Query('companies')) ->setArguments(['serialNumbers' => [159, 260, 371]]) ->setSelectionSet( [ 'name', 'serialNumber' ] );
此查询是参数查询的特殊情况。在此示例中,查询将仅检索序列号为 159、260 或 371 的公司,显示其名称和序列号。
带输入对象参数的查询
$gql = (new Query('companies')) ->setArguments(['filter' => new RawObject('{name_starts_with: "Face"}')]) ->setSelectionSet( [ 'name', 'serialNumber' ] );
这个查询是参数查询的另一种特殊情况。在这个例子中,我们设置了一个自定义输入对象“filter”,并赋予了一些值来限制返回的公司。我们将“name_starts_with”过滤器设置为“Face”。这个查询将仅检索以“Face”短语开头的公司名称。
正在构造的RawObject类用于将字符串直接注入到查询中。输入到RawObject构造函数中的任何字符串都将按原样放入查询中,而不进行查询类通常进行的任何自定义格式化。
带有变量的查询
$gql = (new Query('companies')) ->setVariables( [ new Variable('name', 'String', true), new Variable('limit', 'Int', false, 5) ] ) ->setArguments(['name' => '$name', 'first' => '$limit']) ->setSelectionSet( [ 'name', 'serialNumber' ] );
此查询展示了如何使用此包中的变量在符合GraphQL标准的情况下启用动态请求。
变量类
变量类是一个不可变的类,代表GraphQL标准中的一个变量。其构造函数接收4个参数
- name: 代表变量名称
- type: 代表根据GraphQL服务器模式表示的变量类型
- isRequired(可选):代表变量是否必须,默认为false
- defaultValue(可选):代表分配给变量的默认值。如果将isRequired参数设置为false,则仅考虑默认值。
使用别名
$gql = (new Query()) ->setSelectionSet( [ (new Query('companies', 'TechCo')) ->setArguments(['name' => 'Tech Co.']) ->setSelectionSet( [ 'name', 'serialNumber' ] ), (new Query('companies', 'AnotherTechCo')) ->setArguments(['name' => 'A.N. Other Tech Co.']) ->setSelectionSet( [ 'name', 'serialNumber' ] ) ] );
当需要用不同的参数多次检索相同对象时,可以在Query构造函数的第二个参数中设置别名。
$gql = (new Query('companies')) ->setAlias('CompanyAlias') ->setSelectionSet( [ 'name', 'serialNumber' ] );
别名也可以通过setter方法设置。
使用接口:带有内联片段的查询
当查询返回接口类型的字段时,您可能需要使用内联片段来访问底层具体类型上的数据。
此示例展示了如何使用此包生成内联片段
$gql = new Query('companies'); $gql->setSelectionSet( [ 'serialNumber', 'name', (new InlineFragment('PrivateCompany')) ->setSelectionSet( [ 'boardMembers', 'shareholders', ] ), ] );
查询构建器
QueryBuilder类可用于动态构建查询对象,这在某些情况下可能很有用。它的工作方式与Query类非常相似,但查询构建被分为几个步骤。
这就是如何使用QueryBuilder创建“带有输入对象参数的查询”示例
$builder = (new QueryBuilder('companies')) ->setVariable('namePrefix', 'String', true) ->setArgument('filter', new RawObject('{name_starts_with: $namePrefix}')) ->selectField('name') ->selectField('serialNumber'); $gql = $builder->getQuery();
与Query类一样,可以使用第二个构造函数参数设置别名。
$builder = (new QueryBuilder('companies', 'CompanyAlias')) ->selectField('name') ->selectField('serialNumber'); $gql = $builder->getQuery();
或通过setter方法
$builder = (new QueryBuilder('companies')) ->setAlias('CompanyAlias') ->selectField('name') ->selectField('serialNumber'); $gql = $builder->getQuery();
完整形式
与Query类一样,QueryBuilder类可以完全编写,以启用在一个查询构建器对象下编写多个查询。以下是如何使用QueryBuilder的完整形式的示例
$builder = (new QueryBuilder()) ->setVariable('namePrefix', 'String', true) ->selectField( (new QueryBuilder('companies')) ->setArgument('filter', new RawObject('{name_starts_with: $namePrefix}')) ->selectField('name') ->selectField('serialNumber') ) ->selectField( (new QueryBuilder('company')) ->setArgument('serialNumber', 123) ->selectField('name') ); $gql = $builder->getQuery();
此查询是前一个示例查询的扩展。它返回所有以名称前缀开头且返回具有值为123的serialNumber
的公司,这两个都在同一响应中。
构造客户端
可以通过提供GraphQL端点URL轻松实例化Client对象。
Client构造函数还接收一个可选的“authorizationHeaders”数组,可用于向发送到GraphQL服务器的所有请求中添加授权头。
示例
$client = new Client( 'http://api.graphql.com', ['Authorization' => 'Basic xyz'] );
Client构造函数还接收一个可选的“httpOptions”数组,它将覆盖“authorizationHeaders”,并可用于添加自定义Guzzle HTTP客户端请求选项。
示例
$client = new Client( 'http://api.graphql.com', [], [ 'connect_timeout' => 5, 'timeout' => 5, 'headers' => [ 'Authorization' => 'Basic xyz' 'User-Agent' => 'testing/1.0', ], 'proxy' => [ 'http' => 'tcp://:8125', // Use this proxy with "http" 'https' => 'tcp://:9124', // Use this proxy with "https", 'no' => ['.mit.edu', 'foo.com'] // Don't use a proxy with these ], 'cert' => ['/path/server.pem', 'password'] ... ] );
可以使用您自己的预配置的HTTP客户端,该客户端实现了PSR-18接口。
示例
$client = new Client( 'http://api.graphql.com', [], [], $myHttpClient );
运行查询
结果格式化
使用GraphQL客户端运行查询并获取对象结构化的结果
$results = $client->runQuery($gql); $results->getData()->companies[0]->branches;
或获取数组结构化的结果
$results = $client->runQuery($gql, true); $results->getData()['companies'][1]['branches']['address'];
向查询传递变量
运行包含变量的查询需要传递一个关联数组,该数组将变量名称(键)映射到变量值(值),传递给runQuery
方法。以下是一个示例
$gql = (new Query('companies')) ->setVariables( [ new Variable('name', 'String', true), new Variable('limit', 'Int', false, 5) ] ) ->setArguments(['name' => '$name', 'first' => '$limit']) ->setSelectionSet( [ 'name', 'serialNumber' ] ); $variablesArray = ['name' => 'Tech Co.', 'first' => 5]; $results = $client->runQuery($gql, true, $variablesArray);
突变
变异遵循GraphQL查询相同的规则,它们选择返回对象的字段,接收参数,并且可以有子字段。
以下是一个如何构建和运行变异的示例
$mutation = (new Mutation('createCompany')) ->setArguments(['companyObject' => new RawObject('{name: "Trial Company", employees: 200}')]) ->setSelectionSet( [ '_id', 'name', 'serialNumber', ] ); $results = $client->runQuery($mutation);
变异可以通过与运行查询相同的方式由客户端运行。
带有变量的变异示例
变异可以利用变量与查询相同的方式。以下是如何使用变量动态地将输入对象传递给GraphQL服务器的示例
$mutation = (new Mutation('createCompany')) ->setVariables([new Variable('company', 'CompanyInputObject', true)]) ->setArguments(['companyObject' => '$company']); $variables = ['company' => ['name' => 'Tech Company', 'type' => 'Testing', 'size' => 'Medium']]; $client->runQuery( $mutation, true, $variables );
这些是生成的变异及其传递的变量
mutation($company: CompanyInputObject!) { createCompany(companyObject: $company) } {"company":{"name":"Tech Company","type":"Testing","size":"Medium"}}
实时API示例
GraphQL Pokemon是一个非常酷的公共GraphQL API,可用于检索宝可梦数据。该API公开在网络上,我们将用它来演示此客户端的功能。
Github仓库链接: https://github.com/lucasbento/graphql-pokemon
API链接: https://graphql-pokemon.now.sh/
此查询检索任何宝可梦的进化及其攻击
query($name: String!) { pokemon(name: $name) { id number name evolutions { id number name weight { minimum maximum } attacks { fast { name type damage } } } } }
这就是如何使用查询类编写此查询,并使用客户端运行它
$client = new Client( 'https://graphql-pokemon.now.sh/' ); $gql = (new Query('pokemon')) ->setVariables([new Variable('name', 'String', true)]) ->setArguments(['name' => '$name']) ->setSelectionSet( [ 'id', 'number', 'name', (new Query('evolutions')) ->setSelectionSet( [ 'id', 'number', 'name', (new Query('attacks')) ->setSelectionSet( [ (new Query('fast')) ->setSelectionSet( [ 'name', 'type', 'damage', ] ) ] ) ] ) ] ); try { $name = readline('Enter pokemon name: '); $results = $client->runQuery($gql, true, ['name' => $name]); } catch (QueryError $exception) { print_r($exception->getErrorDetails()); exit; } print_r($results->getData()['pokemon']);
或者,这就是如何使用QueryBuilder类生成此查询
$client = new Client( 'https://graphql-pokemon.now.sh/' ); $builder = (new QueryBuilder('pokemon')) ->setVariable('name', 'String', true) ->setArgument('name', '$name') ->selectField('id') ->selectField('number') ->selectField('name') ->selectField( (new QueryBuilder('evolutions')) ->selectField('id') ->selectField('name') ->selectField('number') ->selectField( (new QueryBuilder('attacks')) ->selectField( (new QueryBuilder('fast')) ->selectField('name') ->selectField('type') ->selectField('damage') ) ) ); try { $name = readline('Enter pokemon name: '); $results = $client->runQuery($builder, true, ['name' => $name]); } catch (QueryError $exception) { print_r($exception->getErrorDetails()); exit; } print_r($results->getData()['pokemon']);
运行原始查询
虽然这不是此包的主要目标,但它支持运行原始字符串查询,就像其他任何客户端一样,使用Client
类中的runRawQuery
方法。以下是如何使用它的示例
$gql = <<<QUERY query { pokemon(name: "Pikachu") { id number name attacks { special { name type damage } } } } QUERY; $results = $client->runRawQuery($gql);