datafield-1.x-dev/src/Plugin/GraphQLCompose/FieldType/DataFieldItem.php
src/Plugin/GraphQLCompose/FieldType/DataFieldItem.php
<?php
namespace Drupal\datafield\Plugin\GraphQLCompose\FieldType;
use Drupal\Core\Field\FieldItemInterface;
use Drupal\graphql\GraphQL\Execution\FieldContext;
use Drupal\graphql_compose\Plugin\GraphQL\DataProducer\FieldProducerItemInterface;
use Drupal\graphql_compose\Plugin\GraphQL\DataProducer\FieldProducerTrait;
use Drupal\graphql_compose\Plugin\GraphQLCompose\GraphQLComposeFieldTypeBase;
use function Symfony\Component\String\u;
/**
* {@inheritDoc}
*/
#[GraphQLComposeFieldType(
id: 'data_field',
)]
class DataFieldItem extends GraphQLComposeFieldTypeBase implements FieldProducerItemInterface {
use FieldProducerTrait;
/**
* {@inheritdoc}
*/
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;
}
/**
* Get the subfield value for a subfield.
*
* @param string $subfield
* The delta of the subfield. (first, second, third)
* @param \Drupal\Core\Field\FieldItemInterface $item
* The field item.
* @param \Drupal\graphql\GraphQL\Execution\FieldContext $context
* The field context.
*
* @return string
* The value of the subfield.
*/
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);
}
/**
* {@inheritdoc}
*
* Override the type resolution for this field item.
*/
public function getTypeSdl(): string {
$type = u('Data');
$settings = $this->getFieldDefinition()->getSetting('columns');
$subfields = array_keys($settings);
foreach ($subfields as $subfield) {
$sub = $this->getSubfieldTypeSdl($subfield);
$type = $type->append(u($sub)->title()->toString());
}
return $type->toString();
}
/**
* Get the subfield type for a subfield.
*
* @param string $subfield
* The subfield to get the type for. Eg first, second, third.
*
* @return string
* The SDL type of the subfield.
*/
public function getSubfieldTypeSdl(string $subfield): string {
$plugin = $this->getSubfieldPlugin($subfield);
return $plugin['type_sdl'] ?? 'String';
}
/**
* Get the data definition type from Triple Field.
*
* @param string $subfield
* The subfield to get the plugin for. Eg first, second, third.
*
* @return array|null
* The plugin definition or NULL if not found.
*/
protected function getSubfieldPlugin(string $subfield): ?array {
$storage = $this->getFieldDefinition()->getFieldStorageDefinition();
$settings = $storage->getSetting('columns');
// Fortunately the types triple_field supports isn't too large.
// @see DataFieldItem::isListAllowed()
$type = $settings[$subfield]['type'];
// Coerce them back into our schema supported type.
switch ($type) {
case 'numeric':
$type = 'decimal';
break;
case 'date':
case 'datetime_iso8601':
$type = 'datetime';
break;
case 'uri':
$type = 'string';
break;
case 'entity_reference':
$type = 'data_entity_reference';
break;
}
return $this->gqlFieldTypeManager->getDefinition($type, FALSE);
}
}
