Support data field

Created on 13 April 2024, 9 months ago
Updated 9 June 2024, 7 months ago

I make patch to support data field . Basically it works exactly like module double field, but data field has more functionality (entity reference, file,...). this patch enables data field in schemas, but in explorer
I have an error

GraphQL\Error\InvariantViolation: DataStringIntFloat fields must be an associative array with field names as keys or a function which returns such an array. in GraphQL\Type\Definition\FieldDefinition::defineFieldMap() (line 110 of C:\wamp64\www\drupal10\vendor\webonyx\graphql-php\src\Type\Definition\FieldDefinition.php).
GraphQL\Type\Definition\TypeWithFields->initializeFields() (Line: 61)
GraphQL\Type\Definition\TypeWithFields->getFields() (Line: 202)
GraphQL\Utils\TypeInfo::extractTypes(Object, Array) (Line: 162)
GraphQL\Utils\TypeInfo::extractTypes(Object, Array) (Line: 222)
GraphQL\Utils\TypeInfo::extractTypes(Object, Array) (Line: 222)
GraphQL\Type\Schema->collectAllTypes() (Line: 208)
GraphQL\Type\Schema->getTypeMap() (Line: 161)
GraphQL\Type\Schema->__construct(Object) (Line: 229)
Drupal\graphql_compose\Plugin\GraphQLComposeSchemaTypeManager->printTypes() (Line: 65)
Drupal\graphql_compose\EventSubscriber\AlterSchemaSubscriber->alterSchema(Object, 'graphql.sdl.alter_schema', Object)
call_user_func(Array, Object, 'graphql.sdl.alter_schema', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch(Object, 'graphql.sdl.alter_schema') (Line: 131)
Drupal\graphql\Plugin\GraphQL\Schema\AlterableComposableSchema->getSchemaDocument(Array) (Line: 123)
Drupal\graphql\Plugin\GraphQL\Schema\SdlSchemaPluginBase->getSchema(Object) (Line: 253)
Drupal\graphql\Entity\Server->configuration() (Line: 199)
Drupal\graphql\Entity\Server->executeOperation(Object) (Line: 27)
Drupal\graphql\GraphQL\Utility\Introspection->introspect(Object) (Line: 87)
Drupal\graphql\Controller\ExplorerController->viewExplorer(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 627)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 704)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Please help.

💬 Support request
Status

Active

Version

2.1

Component

Code

Created by

🇫🇷France lazzyvn paris

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @lazzyvn
  • 🇦🇺Australia almunnings Melbourne, 🇦🇺

    Your array function

    'fields' => fn() => $subFields,
    

    Needs to have array keys. The key is the field name.

    You're returning:

    [
      0 => ['type'..., 'description'],
      1 => ['type'..., 'description'],
    ]
    

    You need to return something like.

    [
      $name => ['type'..., 'description'],
    ]
    

    Try this:

            $types[$field->getTypeSdl()] = new ObjectType([
              'name' => $field->getTypeSdl(),
              'description' => (string) $this->t('A data field is a specialty field provided by the CMS.'),
              'fields' => function () use ($field) {
                $columns = array_keys($field->getFieldDefinition()->getSetting('columns'));
                $subFields = [];
                foreach ($columns as $column) {
                  $subFields[$column] = [
                    'type' => static::type($field->getSubfieldTypeSdl($column)),
                    'description' => (string) $this->t('The @field value of the data field', ['@field' => $column]),
                  ];
                }
                return $subFields;
              },
            ]);
    

    This makes it appear in the schema.

    You'll then need to do a bit of work in your `DataFieldItem` class to return the correct value.

  • 🇦🇺Australia almunnings Melbourne, 🇦🇺
  • 🇫🇷France lazzyvn paris

    thanks i change to

            $subFields = array_combine($columns, array_map(function ($name) use ($field) {
              return [
                'type' => static::type($field->getSubfieldTypeSdl($name)),
                'description' => (string) $this->t('The @field value of the data field', ['@field' => $name]),
              ];
            }, $columns));
    

    Error gone.
    I got values brut, Now i need to convert id of entity reference, file to object, uri id to link, it must do logic in resolveFieldItem

      public function resolveFieldItem(FieldItemInterface $item, FieldContext $context) {
        $columns = array_keys($this->getFieldDefinition()->getSetting('columns'));
        $subfields = [];
        foreach ($columns as $subfield) {
          $subfields[$subfield] = $this->getSubField($subfield, $item, $context) ?: NULL;
        }
        return $subfields;
      }
    

    do you have any service or helper to convert to graphql compose format?

  • 🇫🇷France lazzyvn paris

    Hello,
    I tried the data field with the subfield as the entity reference. It only shows the nid but I want all the node's field value like jsonapi. i try converting object node to array.
    In explorer it shows NULL in subfield, what did I do wrong?

      protected function getSubField(string $subfield, FieldItemInterface $item, FieldContext $context) {
        $value = $item->{$subfield};
    
        // Attempt to load the plugin for the field type.
        $plugin = $this->getSubfieldPlugin($subfield);
        if (!$plugin) {
          return $value;
        }
        $storageSettings = $item->getFieldDefinition()->getSetting('columns')[$subfield];
        $fieldSettings = $item->getFieldDefinition()->getSetting('field_settings')[$subfield];
        if ($storageSettings["type"] == 'entity_reference' && is_numeric($value)) {
          $entity = \Drupal::entityTypeManager()->getStorage($fieldSettings["entity_reference_type"])->load($value);
          $value = [];
          foreach ($entity->getFields() as $name => $field) {
            $value[$name] = $field->getString();
          }
          return $value;
        }
    
  • 🇫🇷France lazzyvn paris

    Please support datafield with entity
    I try but it doesn't work smothly
    https://git.drupalcode.org/project/datafield/-/blob/2.x/src/Plugin/Graph...

    protected function getSubField(string $subfield, FieldItemInterface $item, FieldContext $context) {
        $value = $item->{$subfield};
    
        // Attempt to load the plugin for the field type.
        $plugin = $this->getSubfieldPlugin($subfield);
        if (!$plugin) {
          return $value;
        }
        $storageSettings = $item->getFieldDefinition()->getSetting('columns')[$subfield];
        $fieldSettings = $item->getFieldDefinition()->getSetting('field_settings')[$subfield];
        if ($storageSettings["type"] == 'entity_reference' && is_numeric($value)) {
          $entity = \Drupal::entityTypeManager()->getStorage($fieldSettings["entity_reference_type"])->load($value);
          $item->set('entity', $entity);
          $value = $entity->uuid();
        }
        if ($storageSettings["type"] == 'file' && is_numeric($value)) {
          $entity = \Drupal::entityTypeManager()->getStorage('file')->load($value);
          $item->set('entity', $entity);
        }
        // Check if it has a resolver we can hijack.
        $class = new \ReflectionClass($plugin['class']);
        if (!$class->implementsInterface(FieldProducerItemInterface::class)) {
          return $value;
        }
    
        // Create an instance of the graphql plugin.
        $instance = $this->gqlFieldTypeManager->createInstance($plugin['id'], []);
    
        // Clone the current item into a new object for safety.
        $clone = clone $item;
    
        // Generically set the value. Relies on magic method __set().
        $clone->value = $value;
    
        // Call the plugin resolver on the subfield.
        return $instance->resolveFieldItem($clone, $context);
      }
    
    
Production build 0.71.5 2024