laravel-graphql
laravel-graphql copied to clipboard
Resolving type, need data that I don't have
Sorry if this is in the docs somewhere I looked and didn't see anything. Also looked to see if there was an issue for this.
I have a custom type Row
that needs some data/config for the attributes
to work:
public function fields()
{
$fields = collect($this->fields)
->map(function ($field, $ignored) {
return [
'type' => $this->getType($field),
'description' => array_get($field, 'display'),
'resolve' => [$this, 'resolveField'],
];
});
return $fields->all();
}
I need the $this->fields
to be passed in during instantiation of the RowType. But I don't see in the parent object how to pass this in. This is how it's set in the parent, as part of the fields()
call:
getType method...
return Type::listOf(GraphQL::type('Row'));
in here:
return [
'type' => $this->getType($field),
'description' => array_get($field, 'display'),
'resolve' => [$this, 'resolveField'],
];
If I had this, then I could make Statamic, a wicked CMS built on Laravel, also support GraphQL.
This is needed because the items in a row are defined elsewhere and I don't have enough information in that fields
call to figure it out.
AFAIK the types are "maked" via Laravel, i.e. you can inject any dependency you want via the constructor; did you give this a try?
Sorry, I'm not explaining myself very well.
This is for Statamic. The data definitions are not fixed, so I need a generic solution. Here's an example definition (called a fieldset) of a User:
title: User
hide: true
taxonomies:
class:
max_items: 1
sort: title:desc
sections:
main:
display: Main
fields:
username:
type: text
display: Username
width: 50
email:
type: text
display: Email address
width: 50
first_name:
type: text
display: First Name
width: 50
validate: required
last_name:
type: text
display: Last Name
width: 50
validate: required
roles:
type: user_roles
width: 50
display: Roles
biography:
type: text
width: 50
photo:
type: assets
display: Photo
container: main
folder: screenshots
max_files: 1
restrict: false
width: 50
validate: required
content:
type: textarea
display: Biography
grid:
mode: table
fields:
text:
type: text
display: text
radio:
options:
one: One
two: Two
inline: true
type: radio
display: radio
type: grid
display: grid
And here's what the corresponding data looks like:
---
email: [email protected]
first_name: Erin
last_name: Dalzell
biography: part of my bio changed again
photo: /assets/screenshots/img_0115.jpg
grid:
-
text: row one
radio: two
-
text: row two
radio: two
title: Erin Dalzell
alt_title: Footer
email_id: erin
nickname: emd
middle_name_or_initial: M
super: true
password_hash: $2y$10$p7nkg0zf/5QLFKWXelCwAe.OrJilt8BemDMQzEwbzNKkM6Z985Awq
id: 5e4fe579-8528-4dea-9f27-b6294758b4a3
---
this is a bio that has changed again
Each fieldset can have various fields, each site is different. There are a fixed number of fields, include two that are "lists", grid
and replicator
. I'm focused on grids right now. A grid
is essentially a table, or list of rows, each row having various fields.
The challenge is, when I resolved the Row, I don't have access to the "fieldset" to get the list fields for that row.
HEre's my UserType:
public function fields()
{
$fields = collect(FieldsetAPI::get('user')->fields())
->map(function ($field, $ignored) {
return [
'type' => $this->getType($field),
'description' => array_get($field, 'display'),
'resolve' => [$this, 'resolveField'],
];
})->put('id', [
'type' => Type::nonNull(Type::id()),
'description' => 'The id of the user',
'resolve' => [$this, 'resolveField'],
]);
return $fields->all();
}
// this has to be public for some reason
public function resolveField(User $user, $args, $context, ResolveInfo $info)
{
return array_get($user->toArray(), $info->fieldName);
}
private function getType($field)
{
/**
* @todo how to handle all the different fields types
* @todo how to handle the composite types, like grids of things
* @todo how to handle the "related" types, like relate or taxonomy
* @todo add Date type
*/
switch ($field['type']) {
case 'toggle':
return Type::boolean();
break;
case 'redactor':
case 'template':
case 'text':
case 'textarea':
case 'video':
case 'yaml':
return Type::string();
break;
case 'assets':
case 'checkboxes':
case 'list':
case 'radio':
case 'select':
case 'tags':
if (array_get($field, 'max_files', 1) > 1 ||
array_get($field, 'max_items', 1) > 1) {
return Type::listOf(Type::string());
} else {
return Type::string();
}
break;
case 'bard':
case 'replicator':
break;
case 'grid':
// right here I *DO* have the fields, I'd love to pass something to the RowType, like the list of fields
return Type::listOf(GraphQL::type('Row'));
break;
default:
return Type::listOf(Type::string());
}
}
Because in the RowType fields()
method:
public function fields()
{
$fields = collect($this->fields)
->map(function ($field, $ignored) {
return [
'type' => $this->getType($field),
'description' => array_get($field, 'display'),
'resolve' => [$this, 'resolveField'],
];
});
I need to have the list of fields, which I don't. I can't pass it in the constructor because I don't know it there, and data type might have multiple grids, each with different kinds of rows (different fields).
If the type()
method took a 3rd parameter that was passed into buildObjectTypeFromClass
then I
might have access to it somewhere else, like in the constructor or something.
Sorry if that's not clear, this is hard to write out clearly.