unclecheese

getMyComputedProperty()

  1. fields:
  2. - MyComputedProperty
unclecheese

No. Will be in the future though. SS GraphQL 4.0 will have a very different API. So brace for impact.

unclecheese

We really need to invest in the scaffolding api more.

unclecheese

Ideally we want scaffolding to solve the 80% case. It seems like it falls short in enough areas that people just bail on it and use procedural code.

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