Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Methods corresponding to scaffolded fields can no longer return plain arrays, error message cryptic #430

Open
MasonD opened this issue Jan 6, 2022 · 7 comments

Comments

@MasonD
Copy link
Contributor

MasonD commented Jan 6, 2022

It used to be such that the following would work:

ClassName:
  fields:
    customField:
      type: '[String!]!'
    property: getCustomField
class ClassName extends DataObject {
  // ...
  public function getCustomField() { return ['custom', 'field']; }
}

But now this causes errors reading nl2br(): Argument #1 ($string) must be of type string, array given, which is rather cryptic.

The cause is that, now that scaffolded fields are accessed through ViewableData::obj(), the array goes through the casting process and by default will be cast as a DBString, which will use nl2br when forTemplate is called. There doesn't seem to be a way to achieve the desired result besides instead returning an ArrayList.

(Creating an ArrayList for me seems like not the optimal solution, because it might necessitate creating an extra function specifically for graphql if there's oither code already expecting getCustomField to return a plain array)

I don't know if this is something to fix in some way (however that might be), but if not I think there need to be warnings in the documentation somewhere, or the error caught and given a better error message, because right now somebody not familiar with the internals of silverstripe-graphql will have no idea how to proceed when encountering this error.

@emteknetnz
Copy link
Member

@MasonD which version of graphql are you using? 3 or 4 (master branch)?

@MasonD
Copy link
Contributor Author

MasonD commented Jan 12, 2022

Version 4.

@emteknetnz
Copy link
Member

@unclecheese

@unclecheese
Copy link

Yup, we need to coerce array results into ArrayList.. that's the best option here. I'm thinking....

Extension for all dataobjects provides graphqlObj(), which:

  • hasMethod($field) ?
    • No? go to -> obj($field)
    • Yes?
      • Test the return value.. either execute the method, or
      • Rely on return type definition (e.g. reflection)
      • If array:
        • Wrap it in ArrayList
      • Else -> obj($field)

Then, update all the ->obj references throughout (mostly FieldAccessor) to use graphqlObj

@MasonD
Copy link
Contributor Author

MasonD commented Feb 2, 2022

That seems like a lot of extra introspection to be done on every resolution of a field, if that logic lives in the resolver. Perhaps it can be done at compile time and the resolver can be set as either one that calls obj or one that calls the method and wraps in ArrayList? Or is that premature optimisation...

@unclecheese
Copy link

Nah, this would all happen in the build. You can pass metadata to the resolver at compile time with addResolverContext, e.g. addResolverContext(['isMethodThatReturnsArray', => true])

@bummzack
Copy link
Contributor

bummzack commented May 25, 2022

I've got the same issue when I try to return an array of strings. Wrapping the result in an ArrayList does not help either.
How did you end up solving this issue, @MasonD?

When returning an ArrayList of strings, I now get:

[Emergency] Uncaught TypeError: get_class(): Argument #1 ($object) must be of type object, string given

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

No branches or pull requests

4 participants