Skip to content
This repository has been archived by the owner on Feb 10, 2019. It is now read-only.

Resolving type, need data that I don't have #361

Open
edalzell opened this issue Jul 19, 2018 · 3 comments
Open

Resolving type, need data that I don't have #361

edalzell opened this issue Jul 19, 2018 · 3 comments

Comments

@edalzell
Copy link

edalzell commented Jul 19, 2018

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'],
                    ];
@edalzell
Copy link
Author

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.

@mfn
Copy link

mfn commented Aug 18, 2018

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?

@edalzell
Copy link
Author

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.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants