softonic / graphql-client
Softonic GraphQL 客户端
Requires
- php: ^8.0
- ext-json: *
- guzzlehttp/guzzle: ^6.3 || ^7.0
- softonic/guzzle-oauth2-middleware: ^2.1
- symfony/console: ^6.0 || ^7.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.9
- mockery/mockery: ^1.5
- phpunit/phpunit: ^9.5
- rector/rector: ^0.13.8
- squizlabs/php_codesniffer: ^3.7
README
PHP 客户端用于 GraphQL
主要功能
- 支持 OAuth2 的客户端
- 易于执行查询/突变
- 突变和查询的简单数组结果
- 突变和查询的强大对象结果
- 过滤结果
- 精确和批量操作结果
- 在突变中转换查询结果
安装
通过 composer
composer require softonic/graphql-client
文档
实例化客户端
您可以实例化一个简单的客户端或具有 OAuth2 支持的客户端。
简单客户端
<?php $client = \Softonic\GraphQL\ClientBuilder::build('https://your-domain/graphql');
OAuth2 提供商
此软件包允许您使用 thephpleague/oauth2-client 适配器进行身份验证,因此端点取决于您所使用的适配器。适配器可以是 自定义 或由库作为 官方 或 第三方 提供。
以下是一个使用自定义提供者的示例。
<?php $options = [ 'clientId' => 'myclient', 'clientSecret' => 'mysecret', ]; $provider = new Softonic\OAuth2\Client\Provider\Softonic($options); $config = ['grant_type' => 'client_credentials', 'scope' => 'myscope']; $cache = new \Symfony\Component\Cache\Adapter\FilesystemAdapter(); $client = \Softonic\GraphQL\ClientBuilder::buildWithOAuth2Provider( 'https://your-domain/graphql', $provider, $config, $cache );
使用 GraphQL 客户端
您可以使用客户端执行查询和突变,并获取结果。
<?php /** * Query Example */ $query = <<<'QUERY' query GetFooBar($idFoo: String, $idBar: String) { foo(id: $idFoo) { id_foo bar (id: $idBar) { id_bar } } } QUERY; $variables = [ 'idFoo' => 'foo', 'idBar' => 'bar', ]; /** @var \Softonic\GraphQL\Client $client */ $response = $client->query($query, $variables); if($response->hasErrors()) { // Returns an array with all the errors found. $response->getErrors(); } else { // Returns an array with all the data returned by the GraphQL server. $response->getData(); } /** * Mutation Example */ $mutation = <<<'MUTATION' mutation ($foo: ObjectInput!){ CreateObjectMutation (object: $foo) { status } } MUTATION; $variables = [ 'foo' => [ 'id_foo' => 'foo', 'bar' => [ 'id_bar' => 'bar' ] ] ]; /** @var \Softonic\GraphQL\Client $client */ $response = $client->query($mutation, $variables); if($response->hasErrors()) { // Returns an array with all the errors found. $response->getErrors(); } else { // Returns an array with all the data returned by the GraphQL server. $response->getData(); }
在前面的示例中,客户端用于执行查询和突变。响应对象用于以数组格式获取结果。
这对于简单用例来说可能很方便,但不建议用于复杂结果或需要使用该输出生成突变的情况。因此,客户端提供另一种输出,称为数据对象。这些对象允许您以更方便的格式获取结果,让您生成突变、应用过滤器等。
如何使用数据对象并将其转换为突变查询
查询结果可以作为对象获取,它将提供将它们转换为突变并轻松修改数据的便利设施。最后,突变对象将能够用作 GraphQL 客户端中突变查询的变量。
首先,我们执行一个 "读取" 查询,并将结果作为由 Items 和 Collections 组成的对象复合体获取。
$response = $client->query($query, $variables); $data = $response->getDataObject(); /** * $data = new QueryItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_author' => 1234, * 'genre' => 'adventure', * 'chapters' => new QueryCollection([ * new QueryItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 1, * 'name' => 'Chapter One', * 'pov' => 'first person', * 'pages' => new QueryCollection([]), * ]), * new QueryItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'name' => 'Chapter two', * 'pov' => 'third person', * 'pages' => new QueryCollection([ * new QueryItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 1, * 'has_illustrations' => false, * ]), * new QueryItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 2, * 'has_illustrations' => false, * ]), * ]), * ]), * ]), * ]); */
我们还可以过滤结果,以便稍后使用更少的数据。过滤器方法返回一个包含过滤结果的新对象,因此如果您想修改它,则需要将对象重新分配到原始对象。
$data->chapters = $data->chapters->filter(['pov' => 'third person']); /** * $data = new QueryItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_author' => 1234, * 'genre' => 'adventure', * 'chapters' => new QueryCollection([ * new QueryItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'name' => 'Chapter two', * 'pov' => 'third person', * 'pages' => new QueryCollection([ * new QueryItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 1, * 'has_illustrations' => false, * ]), * new QueryItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 2, * 'has_illustrations' => false, * ]), * ]), * ]), * ]), * ]); */
然后,我们可以从先前的查询结果生成突变变量对象。这是使用突变配置构建的。每个类型的配置具有以下参数
- linksTo:查询结果对象中可以获取该类型数据的位置。如果不存在,则表示该级别没有来自源的数据。
- type:突变对象类型(Item 或 Collection)。
- children:如果突变有一个键,其值是另一个突变类型。
$mutationConfig = [ 'book' => [ 'linksTo' => '.', 'type' => MutationItem::class, 'children' => [ 'chapters' => [ 'type' => MutationItem::class, 'children' => [ 'upsert' => [ 'linksTo' => '.chapters', 'type' => MutationCollection::class, 'children' => [ 'pages' => [ 'type' => MutationItem::class, 'children' => [ 'upsert' => [ 'linksTo' => '.chapters.pages', 'type' => MutationCollection::class, ], ], ], ], ], ], ], ], ], ]; $mutation = Mutation::build($mutationConfig, $data); /** * $mutation = new MutationItem([ * 'book' => new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_author' => 1234, * 'genre' => 'adventure', * 'chapters' => new MutationItem([ * 'upsert' => new MutationCollection([ * new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 1, * 'name' => 'Chapter One', * 'pov' => 'first person', * 'pages' => new MutationItem([ * 'upsert' => new MutationCollection([]), * ]), * ]), * new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'name' => 'Chapter two', * 'pov' => 'third person', * 'pages' => new MutationItem([ * 'upsert' => new MutationCollection([ * new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 1, * 'has_illustrations' => false, * ]), * new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 2, * 'has_illustrations' => false, * ]), * ]), * ]), * ]), * ]), * ]), * ]), * ]); */
现在我们可以使用以下方法修改突变数据
- add():向 Collection 中添加一个 Item。
- set():更新 Item 的某些值。它也适用于 Collection,更新其所有 Item。
- filter():过滤 Collection 中的 Item。
- count():计算 Collection 中的 Item 数量。
- isEmpty(): 检查一个集合是否为空。
- has(): 检查一个项目是否有参数。也适用于集合。也允许点表示法。
- hasItem(): 检查集合中是否包含具有提供数据的项。
- remove(): 从集合中移除一个项目。
- __unset(): 从项目或集合中所有项目移除属性。
$mutation->book->chapters->upsert->filter(['id_chapter' => 2])->pages->upsert->add([ 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', 'id_chapter' => 2, 'id_page' => 3, 'has_illustrations' => false, ]); $mutation->book->chapters->upsert->pages->upsert->filter([ 'id_chapter' => 2, 'id_page' => 2, ])->set(['has_illustrations' => true]); $itemToRemove = new MutationItem([ 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', 'id_chapter' => 2, 'id_page' => 1, 'has_illustrations' => false, ]); $mutation->book->chapters->upsert->files->upsert->remove($itemToRemove); unset($mutation->book->chapters->upsert->pov); /** * $mutation = new MutationItem([ * 'book' => new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_author' => 1234, * 'genre' => 'adventure', * 'chapters' => new MutationItem([ * 'upsert' => new MutationCollection([ * new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 1, * 'name' => 'Chapter One', * 'pages' => new MutationItem([ * 'upsert' => new MutationCollection([]), * ]), * ]), * new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'name' => 'Chapter two', * 'pages' => new MutationItem([ * 'upsert' => new MutationCollection([ * new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 2, * 'has_illustrations' => true, * ]), * new MutationItem([ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 3, * 'has_illustrations' => false, * ]), * ]), * ]), * ]), * ]), * ]), * ]), * ]); */
最后,修改后的突变数据可以传递给GraphQL客户端以执行突变。当查询执行时,突变变量使用json_encode()进行编码。这修改了仅返回更改的项目及其父项目的突变数据。
$mutationQuery = <<<'QUERY' mutation ($book: BookInput!){ ReplaceBook (book: $book) { status } } QUERY; $client->mutate($mutationQuery, $mutation);
因此,最终发送到查询的变量将是
/** * $mutation = [ * 'book' => [ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_author' => 1234, * 'genre' => 'adventure', * 'chapters' => [ * 'upsert' => [ * [ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'name' => 'Chapter two', * 'pages' => [ * 'upsert' => [ * [ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 2, * 'has_illustrations' => true, * ], * [ * 'id_book' => 'f7cfd732-e3d8-3642-a919-ace8c38c2c6d', * 'id_chapter' => 2, * 'id_page' => 3, * 'has_illustrations' => false, * ], * ], * ], * ], * ], * ], * ], * ]; */
注意2:示例是为根项目"book"执行的,但它也适用于根对象为集合的情况。
测试
softonic/graphql-client
有一个 PHPUnit 测试套件,以及使用 PHP CS Fixer 的编码风格合规性测试套件。
要运行测试,请从项目文件夹中运行以下命令。
$ make tests
在开发环境中打开终端
$ make debug
许可证
Apache 2.0 许可证。有关更多信息,请参阅 LICENSE。