Skip to content

Instantly share code, notes, and snippets.

@n8jadams
Last active October 11, 2019 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save n8jadams/54e3c5d29771c3a2875cf91925ff0a12 to your computer and use it in GitHub Desktop.
Save n8jadams/54e3c5d29771c3a2875cf91925ff0a12 to your computer and use it in GitHub Desktop.
GraphQLQueryChecker. A PHP Class that checks if a field is requested in the query. I've used this in production with webonyx/graphql-php v0.9.14 for more than a year.
<?php
/**
* Instructions:
* In an Object Resolve function, use the fourth argument ($info)
*
* Example usage:
*
* $fieldInQuery = GraphQLQueryChecker::isFieldInQuery('some.nested.fieldname', $info);
*
* If the query looks like this:
*
* query() {
* myObject {
* something
* some {
* nested {
* fieldname
* }
* }
* }
* }
*
* It will be true.
*
* If it looks like this:
* query() {
* myObject {
* something
* some {
* nested {
* field
* }
* }
* }
* }
*
* It will return false.
*
* This is useful if you have some fields that are expensive to calculate
* and want to optimize if those fields aren't requested.
*
*/
class GraphQLQueryChecker
{
public static $found = false;
public static $fields = [];
// If you pass the $info field from a GraphQL resolve function, we can
// recursively check the body of the passed query to determine if a
// field is present. $fieldPath are dot separated fields. Ex: edges.node.id
public static function isFieldInQuery($fieldPath, $info) {
self::$fields = explode('.', $fieldPath);
self::$found = false;
foreach($info->fieldNodes as $fn) {
if(!empty($fn->selectionSet)) {
self::recursiveCheck(self::$fields[0], $fn->selectionSet->selections);
}
}
return self::$found;
}
private static function recursiveCheck($field, $selections) {
foreach($selections as $selection) {
$nextField = self::getNextField($field);
if($selection->name->value === $field && $nextField === null) {
self::$found = true;
break;
} else if($selection->name->value === $field && !empty($selection->selectionSet)) {
self::recursiveCheck($nextField, $selection->selectionSet->selections);
break;
} else if(!empty($selection->selectionSet)) {
self::recursiveCheck($field, $selection->selectionSet->selections);
}
}
}
private static function getNextField($prevField) {
for($i = 0; $i<count(self::$fields); $i++) {
if($prevField === self::$fields[$i]) {
return self::$fields[$i + 1];
}
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment