php-graphql-client icon indicating copy to clipboard operation
php-graphql-client copied to clipboard

Make it possible to get arguments and field name

Open eiriksm opened this issue 1 year ago • 2 comments

Thanks for this library. For me it's super important to represent the query as an object, and this library seems to do the trick nicely. However, it's missing 2 things I need, which this PR adds:

A getter for field name and a getter for arguments.

First. Here is a simple program to illustrate why I want a getter for arguments:

<?php

require_once __DIR__ . '/vendor/autoload.php';

$gql = (new \GraphQL\Query('things'))
  ->setArguments([
    'someClientId' => 'someValueBasedOnCodebase'
  ]);

echo (string) $gql;

// This prints:
// query {
//things(someClientId: "someValueBasedOnCodebase")
//}

// Response is queued and serialized and deserialized, and now all I have back
// is the query object and a cursor id, and I want to just append some arguments
// to it.
$cursor_id = 'someCursor';
$new_args = $gql->getArguments();
$gql->setArguments(array_merge($new_args, [
  'after' => $cursor_id
]));

echo (string) $gql;
// With this PR this prints:
// query {
//things(someClientId: "someValueBasedOnCodebase" after: "someCursor")
//}

And here is why I want the getter for field name:

<?php

require_once __DIR__ . '/vendor/autoload.php';

$gql = (new \GraphQL\Query('things'))
  ->setSelectionSet([
    'id',
    'name',
    (new \GraphQL\Query('subThings'))
      ->setArguments([
        'filter' => 'providerId123',
      ])
      ->setSelectionSet([
        'id',
        'name'
      ])
  ]);

echo (string) $gql;
// This prints:
// query{
//  things {
//    id
//    name
//    subThings(filter: "providerId123") {
//      id
//      name
//    }
//  }
//}

// Well that's all good. But what if I have 20 customers, and they all use the
// library I wrote to retrieve "things", but they have maybe different provider
// ids, and maybe even different fields they want to select. How about doing it
// like this in just a custom override for those where I need it:

$sets = $gql->getSelectionSet();
foreach ($sets as $set) {
  if (!$set instanceof \GraphQL\Query) {
    continue;
  }
  $name = $set->getFieldName();
  if ($name !== 'subThings') {
    continue;
  }
  $set->setArguments(['filter' => 'providerId456']);
  $set->setSelectionSet(array_merge($set->getSelectionSet(), [
    'someField',
    'someOtherField'
  ]));
}

echo (string) $gql;
// With this PR applied, this now is possible and prints:
// query {
//  things {
//    id
//    name
//    subThings(filter: "providerId456") {
//      id
//      name
//      someField
//      someOtherField
//    }
//  }
//}

eiriksm avatar Nov 05 '23 19:11 eiriksm

I'm torn between trying to follow the style in the test class here and the feedback from CI systems, so I will just say that this seems to be good enough, and close enough to the initial code style :)

eiriksm avatar Nov 05 '23 20:11 eiriksm

Especially the fieldname getter interests me as well. It would allow me to implement a simple generic pagination method by extracting the fieldname so I can do something like

$fieldName = $query->fieldname;
$items = $client->runQuery($query)->getResults();

$hasNextPage = $items->data->$fieldName->pageInfo->hasNextPage;
$after = $items->data->$fieldName->pageInfo->endCursor;

wlouckx avatar Mar 14 '24 14:03 wlouckx