softonic/graphql-client

Softonic GraphQL 客户端

3.0.0 2024-03-01 09:31 UTC

This package is auto-updated.

Last update: 2024-08-30 10:43:28 UTC


README

Latest Version Software License Build Status Total Downloads Average time to resolve an issue Percentage of issues still open

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