graphql php入门:如何从.graphql文件向模式添加解析器函数?
我对GraphQL完全是新手,希望通过使用GraphQL php构建一个简单的API来入门。我目前正在阅读文档并尝试示例,但我在一开始就被卡住了 我希望我的模式存储在一个graphql php入门:如何从.graphql文件向模式添加解析器函数?,graphql,graphql-php,Graphql,Graphql Php,我对GraphQL完全是新手,希望通过使用GraphQL php构建一个简单的API来入门。我目前正在阅读文档并尝试示例,但我在一开始就被卡住了 我希望我的模式存储在一个schema.graphql文件中,而不是手动构建它,因此我按照文档中的说明进行了操作,它确实起到了作用: <?php // graph-ql is installed via composer require('../vendor/autoload.php'); use GraphQL\Language\Parser;
schema.graphql
文件中,而不是手动构建它,因此我按照文档中的说明进行了操作,它确实起到了作用:
<?php
// graph-ql is installed via composer
require('../vendor/autoload.php');
use GraphQL\Language\Parser;
use GraphQL\Utils\BuildSchema;
use GraphQL\Utils\AST;
use GraphQL\GraphQL;
try {
$cacheFilename = 'cached_schema.php';
// caching, as recommended in the docs, is disabled for testing
// if (!file_exists($cacheFilename)) {
$document = Parser::parse(file_get_contents('./schema.graphql'));
file_put_contents($cacheFilename, "<?php\nreturn " . var_export(AST::toArray($document), true) . ';');
/*} else {
$document = AST::fromArray(require $cacheFilename); // fromArray() is a lazy operation as well
}*/
$typeConfigDecorator = function($typeConfig, $typeDefinitionNode) {
// In the docs, this function is just empty, but I needed to return the $typeConfig, otherwise I got an error
return $typeConfig;
};
$schema = BuildSchema::build($document, $typeConfigDecorator);
$context = (object)array();
// this has been taken from one of the examples provided in the repo
$rawInput = file_get_contents('php://input');
$input = json_decode($rawInput, true);
$query = $input['query'];
$variableValues = isset($input['variables']) ? $input['variables'] : null;
$rootValue = ['prefix' => 'You said: '];
$result = GraphQL::executeQuery($schema, $query, $rootValue, $context, $variableValues);
$output = $result->toArray();
} catch (\Exception $e) {
$output = [
'error' => [
'message' => $e->getMessage()
]
];
}
header('Content-Type: application/json; charset=UTF-8');
echo json_encode($output);
例如,我可以用
query {
__schema {types{name}}
}
这将按预期返回元数据。当然,现在我想查询实际的产品数据,并从数据库中获取数据,为此我需要定义一个解析器函数
文档状态为:“默认情况下,这样的模式是在没有任何解析程序的情况下创建的。我们必须依赖默认字段解析程序和根值,才能对该模式执行查询。”-但没有这样做的示例
如何为每个类型/字段添加解析器函数 这是我最后做的事
$rootResolver = array(
'emptyCart' => function($root, $args, $context, $info) {
global $rootResolver;
initSession();
$_SESSION['CART']->clear();
return $rootResolver['getCart']($root, $args, $context, $info);
},
'addCartProduct' => function($root, $args, $context, $info) {
global $rootResolver;
...
return $rootResolver['getCart']($root, $args, $context, $info);
},
'removeCartProduct' => function($root, $args, $context, $info) {
global $rootResolver;
...
return $rootResolver['getCart']($root, $args, $context, $info);
},
'getCart' => function($root, $args, $context, $info) {
initSession();
return array(
'count' => $_SESSION['CART']->quantity(),
'total' => $_SESSION['CART']->total(),
'products' => $_SESSION['CART']->getProductData()
);
},
然后在配置中
$config = ServerConfig::create()
->setSchema($schema)
->setRootValue($rootResolver)
->setContext($context)
->setDebug(DEBUG_MODE)
->setQueryBatching(true)
;
$server = new StandardServer($config);
对我来说,这感觉有点像黑客,我可能应该将解析器外包到单独的文件中,但它是有效的。。。仍然感到困惑的是,这个任务没有简单的示例,可能比我的解决方案更好……这种方法在不实例化服务器的情况下工作。在我的例子中,我已经有了一个服务器,可以读取HTTP数据,我所需要的只是读取GraphQL模式并运行查询。首先,我从文件中读取模式:
$schemaContent = // file_get_contents or whatever works for you
$schemaDocument = GraphQL\Language\Parser::parse($schemaContent);
$schemaBuilder = new GraphQL\Utils\BuildSchema($schemaDocument);
$schema = $schemaBuilder->buildSchema();
然后,我通过自定义字段解析器执行查询:
$fieldResolver = function() {
return call_user_func_array([$this, 'defaultFieldResolver'], func_get_args());
};
$result = GraphQL\GraphQL::executeQuery(
$schema,
$query, // this was grabbed from the HTTP post data
null,
$appContext, // custom context
$variables, // this was grabbed from the HTTP post data
null,
$fieldResolver // HERE, custom field resolver
);
字段解析程序如下所示:
private static function defaultFieldResolver(
$source,
$args,
$context,
\GraphQL\Type\Definition\ResolveInfo $info
) {
$fieldName = $info->fieldName;
$parentType = $info->parentType->name;
if ($source === NULL) {
// this is the root value, return value depending on $fieldName
// ...
} else {
// Depending on field type ($parentType), I call different field resolvers.
// Since our system is big, we implemented a bootstrapping mechanism
// so modules can register field resolvers in this class depending on field type
// ...
// If no field resolver was defined for this $parentType,
// we just rely on the default field resolver provided by graphql-php (copy/paste).
$fieldName = $info->fieldName;
$property = null;
if (is_array($source) || $source instanceof \ArrayAccess) {
if (isset($source[$fieldName])) {
$property = $source[$fieldName];
}
} else if (is_object($source)) {
if (isset($source->{$fieldName})) {
$property = $source->{$fieldName};
}
}
return $property instanceof \Closure
? $property($source, $args, $context)
: $property;
}
}
我正在为此使用根值:
<?php
require("vendor/autoload.php") ;
require("exemplo-graphql.php");
require("Usuario.php");
use GraphQL\GraphQL;
use GraphQL\Type\Schema;
use GraphQL\Utils\BuildSchema;
$query = $_REQUEST['query'];
$typeConfigDecorator = function($typeConfig, $typeDefinitionNode) {
$name = $typeConfig['name'];
// ... add missing options to $typeConfig based on type $name
return $typeConfig;
};
$contents = file_get_contents('schema.graphql');
$schema = BuildSchema::build($contents, $typeConfigDecorator);
// $rawInput = file_get_contents('php://input');
$input = json_decode($query, true);
$query = $input['query'];
$variableValues = isset($input['variables']) ? $input['variables'] : null;
try {
// $rootValue = ['prefix' => 'You said: '];
$rootValue = [
'usuario' => function($root, $args, $context, $info) {
$usuario = new Usuario();
$usuario->setNome("aqui tem um teste");
$usuario->setEmail("aqui tem um email");
return $usuario;
},
'echo' => function($root, $args, $context, $info) {
return "aqui tem um echooo";
},
'adicionarUsuario' => function ($root, $args, $context, $info) {
$usuario = new Usuario();
$usuario->setNome("aqui tem um teste");
$usuario->setEmail("aqui tem um email");
return $usuario;
}
];
$result = GraphQL::executeQuery($schema, $query, $rootValue, null,
$variableValues);
if ($result->errors) {
$output = [
'errors' => [
[
'message' => $result->errors
]
]
];
} else {
$output = $result->toArray();
}
} catch (\Exception $e) {
$output = [
'errors' => [
[
'message' => $e->getMessage()
]
]
];
}
header('Content-Type: application/json');
echo json_encode($output);
你自己找到答案了吗?如果愿意,可以在这里分享吗?谢谢您好@Seb,我在下面发布了一个答案。我发现了一种不同的方法,它感觉也很粗糙,但它不需要创建服务器就可以工作,并将其添加为子孙后代的答案(?)这对我的应用程序来说变得更重要了,现在有了graphql网页包加载程序。我重复了很多工作,将模式定义为一组大型PHP数组,然后从大型字符串构建客户端查询。我可以将.graphql
文件加载到buildSchema
服务器端,并将import
加载到客户端,从而确保定义保持同步。我发现siler库有一种很好的加载graphql的方法(加载模式,然后加载解析器),但它只是在graphql php之上。您可以查看他们的代码,看看它是如何完成的——看起来他们经常使用GraphQL\Executor\Executor
来设置解析器。
<?php
require("vendor/autoload.php") ;
require("exemplo-graphql.php");
require("Usuario.php");
use GraphQL\GraphQL;
use GraphQL\Type\Schema;
use GraphQL\Utils\BuildSchema;
$query = $_REQUEST['query'];
$typeConfigDecorator = function($typeConfig, $typeDefinitionNode) {
$name = $typeConfig['name'];
// ... add missing options to $typeConfig based on type $name
return $typeConfig;
};
$contents = file_get_contents('schema.graphql');
$schema = BuildSchema::build($contents, $typeConfigDecorator);
// $rawInput = file_get_contents('php://input');
$input = json_decode($query, true);
$query = $input['query'];
$variableValues = isset($input['variables']) ? $input['variables'] : null;
try {
// $rootValue = ['prefix' => 'You said: '];
$rootValue = [
'usuario' => function($root, $args, $context, $info) {
$usuario = new Usuario();
$usuario->setNome("aqui tem um teste");
$usuario->setEmail("aqui tem um email");
return $usuario;
},
'echo' => function($root, $args, $context, $info) {
return "aqui tem um echooo";
},
'adicionarUsuario' => function ($root, $args, $context, $info) {
$usuario = new Usuario();
$usuario->setNome("aqui tem um teste");
$usuario->setEmail("aqui tem um email");
return $usuario;
}
];
$result = GraphQL::executeQuery($schema, $query, $rootValue, null,
$variableValues);
if ($result->errors) {
$output = [
'errors' => [
[
'message' => $result->errors
]
]
];
} else {
$output = $result->toArray();
}
} catch (\Exception $e) {
$output = [
'errors' => [
[
'message' => $e->getMessage()
]
]
];
}
header('Content-Type: application/json');
echo json_encode($output);