View more context

 

nils

Has anyone got any examples of how to use a custom nested query using ListQueryScaffolder? I keep getting this:

  1. "SilverStripe\\GraphQL\\Scaffolding\\Scaffolders\\OperationScaffolder resolver must be a closure or implement SilverStripe\\GraphQL\\OperationResolver"
unclecheese

Might have some time to debug this today. Can you share your code?

nils

Need to check if I got it stashed, ended up doing something else in the end

MichalKleiner

well, a string, as you can either pass a URL of the file or stringified (e.g. base64 encoded) file content

unclecheese

@Anthony van Beek There's a file type provided for you. See graphql/_config/assets.yml

👍 (1)
MichalKleiner

nice, didn’t know about that.. it exposes a bit more than the URL but it’s still a bunch of strings 😄

Anthony van Beek

Getting this error now, reverted all my changes and flushed, won't go away.

unclecheese

'Hero' => $this->manager->getType(StaticSchema::inst()->typeName(File::class))

👍 (1)
Anthony van Beek

hahaha, now got this

  1. "errors": [
  2. {
  3. "message": "Type 'SilverStripe_Assets_File' is not a registered GraphQL type",
Anthony van Beek

but under scaffolding types I have:

  1. SilverStripe\Assets\File:
  2. fieldsExcept: [Content]
  3. fields: [File]
Anthony van Beek

In my Course class I define Hero as

  1. private static $has_one = array(
  2. 'Hero' => Image::class,
  3. );
Anthony van Beek

I changed it to 'Hero' => $this->manager->getType(StaticSchema::inst()->typeName(DBFile::class)),

Anthony van Beek

now I get

  1. [Emergency] Uncaught Error: Cannot use object of type GraphQL\Type\Definition\ObjectType as array
  2. POST /graphql/
  3. Line 172 in /vagrant/vendor/silverstripe/graphql/src/TypeCreator.php
  4.  
  5. Source
  6. 163 * or resolveField().
  7. 164 *
  8. 165 * @param string $name Name of the field
  9. 166 * @param array $field Field array specification
  10. 167 * @return callable|null The callback, or null if there is no field resolver
  11. 168 */
  12. 169 protected function getFieldResolver($name, $field)
  13. 170 {
  14. 171 // Preconfigured method
  15. 172 if (isset($field['resolve'])) {
  16. 173 return $field['resolve'];
  17. 174 }
  18. 175 $candidateMethods = [
  19. 176 'resolve'.ucfirst($name).'Field',
  20. 177 'resolveField',
  21. 178 ];
Anthony van Beek

Ok so I got 'Hero' => ['type' => $this->manager->getType(StaticSchema::inst()->typeName(DBFile::class))],

Anthony van Beek

back to this error

  1. [Notice] Undefined index: type
  2. POST /graphql/
  3. Line 142 in /vagrant/vendor/webonyx/graphql-php/src/Type/Definition/FieldDefinition.php
  4.  
  5. Source
  6. 133 }
  7. 134
  8. 135 /**
  9. 136 * FieldDefinition constructor.
  10. 137 * @param array $config
  11. 138 */
  12. 139 protected function __construct(array $config)
  13. 140 {
  14. 141 $this->name = $config['name'];
  15. 142 $this->type = $config['type'];
  16. 143 $this->resolveFn = isset($config['resolve']) ? $config['resolve'] : null;
  17. 144 $this->mapFn = isset($config['map']) ? $config['map'] : null;
  18. 145 $this->args = isset($config['args']) ? FieldArgument::createMap($config['args']) : [];
  19. 146
  20. 147 $this->description = isset($config['description']) ? $config['description'] : null;
  21. 148 $this->deprecationReason = isset($config['deprecationReason']) ? $config['deprecationReason'] : null;
Anthony van Beek

So I assume I need to to add DBFile into my types

Anthony van Beek

Did that now I got:

  1. [Emergency] Uncaught InvalidArgumentException: "SilverStripe\Assets\Storage\DBFile" is not a DataObject subclass
  2. GET /dev/graphiql?flush=1&flushtoken=d846b537df35fd67c13ff607cc88473a
  3. Line 77 in /vagrant/vendor/silverstripe/graphql/src/Scaffolding/Traits/DataObjectTypeTrait.php
  4.  
  5. Source
  6. 68 if (!$class) {
  7. 69 throw new InvalidArgumentException("Missing class provided");
  8. 70 }
  9. 71
  10. 72 if (!class_exists($class)) {
  11. 73 throw new InvalidArgumentException("Non-existent classname \"{$class}\"");
  12. 74 }
  13. 75
  14. 76 if (!is_subclass_of($class, DataObject::class)) {
  15. 77 throw new InvalidArgumentException("\"{$class}\" is not a DataObject subclass");
  16. 78 }
  17. 79
  18. 80 $this->dataObjectClass = $class;
  19. 81 return $this;
  20. 82 }
  21. 83 }
unclecheese

It should be added in SchemaScaffolder::registerFixedTypes, no?

unclecheese

huh.. can you debug why SchemaScaffolder isn't adding it in registerFixedTypes?

Anthony van Beek

should I add SchemaScaffolder::registerFixedTypes somewhere?

unclecheese

no, it should be called in SchemaScaffolder::addToManager.. can you debug that?

Anthony van Beek

I’ve added

  1. public function addToManager(Manager $manager)
  2. {
  3. dump('running manager');
  4. dump($manager);
unclecheese

just for fun, try wrapping the return statement for your fields() function in a closure. I can't remember if that's allowed or not.

unclecheese

function { return ['ID' => ['type' ...] ] } etc..

Anthony van Beek

mmmmm this is currently my function

  1. public function fields()
  2. {
  3. $courseConnection = Connection::create('Topics')
  4. ->setConnectionType(function () {
  5. return $this->manager->getType('Topic');
  6. })
  7. ->setDescription('A list of the Topics')
  8. ->setSortableFields(['ID', 'Title']);
  9.  
  10. return [
  11. 'ID' => ['type' => Type::nonNull(Type::id())],
  12. 'Title' => ['type' => Type::string()],
  13. 'Estimate' => ['type' => Type::string()],
  14. 'Audience' => ['type' => Type::string()],
  15. 'Content' => ['type' => Type::string()],
  16. 'Hero' => ['type' => $this->manager->getType(StaticSchema::inst()->typeName(DBFile::class))],
  17. 'URLSegment' => ['type ' => Type::string()],
  18. 'Topics' => [
  19. 'type' => $courseConnection->toType(),
  20. 'args' => $courseConnection->args(),
  21. 'resolve' => function ($object, array $args, $context) use ($courseConnection) {
  22. return $courseConnection->resolveList(
  23. $object->Topics(),
  24. $args,
  25. $context
  26. );
  27. }
  28. ]
  29. ];
  30. }
Anthony van Beek

This is what my graphql.yml file looks like :

  1. SilverStripe\GraphQL\Manager:
  2. schemas:
  3. default:
  4. types:
  5. Course: myProject\CourseTypeCreator
  6. ...
  7. mutations:
  8. ...
  9. queries:
  10. ...
  11. scaffolding:
  12. types:
  13. Page:
  14. ...
  15. myProject\Topic:
  16. ...
  17. typeNames:
  18. DNADesign\Elemental\Models\BaseElement: Block
  19. DNADesign\Elemental\Models\ElementalArea: ElementalArea
  20. myProject\Topic: Topic
  21. ...
unclecheese
  1. return function () {
  2. return [
  3. 'ID' => ['type' => Type::nonNull(Type::id())],
Anthony van Beek
  1. Error: Course fields must be an object with field names as keys or a function which returns such an object.
  2. at invariant (http://sorted-website.local:8080/resources/vendor/silverstripe/graphql-devtools/client/dist/graphiql.js?m=1557276366:25910:12)
  3. at defineFieldMap (http://sorted-website.local:8080/resources/vendor/silverstripe/graphql-devtools/client/dist/graphiql.js?m=1557276366:26708:28)
  4. at GraphQLObjectType.getFields (http://sorted-website.local:8080/resources/vendor/silverstripe/graphql-devtools/client/dist/graphiql.js?m=1557276366:26674:45)
  5. at http://sorted-website.local:8080/resources/vendor/silverstripe/graphql-devtools/client/dist/graphiql.js?m=1557276366:26364:28
  6. at typeMapReducer (http://sorted-website.local:8080/resources/vendor/silverstripe/graphql-devtools/client/dist/graphiql.js?m=1557276366:26376:8)
  7. at http://sorted-website.local:8080/resources/vendor/silverstripe/graphql-devtools/client/dist/graphiql.js?m=1557276366:26374:23
  8. at Array.forEach (<anonymous>)
  9. at http://sorted-website.local:8080/resources/vendor/silverstripe/graphql-devtools/client/dist/graphiql.js?m=1557276366:26365:30
  10. at typeMapReducer (http://sorted-website.local:8080/resources/vendor/silverstripe/graphql-devtools/client/dist/graphiql.js?m=1557276366:26376:8)
  11. at typeMapReducer (http://sorted-website.local:8080/resources/vendor/silverstripe/graphql-devtools/client/dist/graphiql.js?m=1557276366:26344:13)
unclecheese

I wonder if that registerFixedTypes needs to be abstracted out of SchemaScaffolder, since it applies to non-scaffolded schema, too.

unclecheese

it's almost like fixed_types needs to be a config property of Manager, not SchemaScaffolder.

Anthony van Beek

Well I could just scaffold the Course which worked previously

unclecheese

Is there a reason you're using the typecreator in lieu of scaffolding? I know there are many, but I'm curious what your reasoning is here, because it seems straightforward.

Anthony van Beek

I was looking at adding in my own custom fields to the graphql response.

eg. I want to calculate the progress of a course and add it as a field into the Course response

unclecheese

Computed properties work in the scaffolder, though.. getCourseProgress() can be declared as fields: { CourseProgress }

Anthony van Beek

The problem that lead me down that rabbit hole is that fields: '*' doesn’t pick up the computed properties.

unclecheese

i often wonder if we could expose those through docblocks


Show less replies
Anthony van Beek

What is the best way to get the currently logged in user in my model?

Anthony van Beek

Security::getCurrentUser(); works in dev/graphiqp but not from my SPA which uses token auth.