View source
<?php
namespace Drupal\graphql\Form;
use Drupal\Component\Plugin\ConfigurableInterface;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformState;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\Routing\RequestContext;
use Drupal\graphql\Plugin\SchemaPluginManager;
use GraphQL\Error\DebugFlag;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ServerForm extends EntityForm {
protected $requestContext;
protected $schemaManager;
public function __construct(SchemaPluginManager $schemaManager, RequestContext $requestContext) {
$this->requestContext = $requestContext;
$this->schemaManager = $schemaManager;
}
public static function create(ContainerInterface $container) : self {
return new static($container
->get('plugin.manager.graphql.schema'), $container
->get('router.request_context'));
}
public function ajaxSchemaConfigurationForm(array $form) {
$response = new AjaxResponse();
$response
->addCommand(new ReplaceCommand('#edit-schema-configuration-plugin-wrapper', $form['schema_configuration']));
return $response;
}
public function form(array $form, FormStateInterface $formState) : array {
$form = parent::form($form, $formState);
$server = $this->entity;
$schemas = array_map(function ($definition) {
return $definition['name'] ?? $definition['id'];
}, $this->schemaManager
->getDefinitions());
$schema_keys = array_keys($schemas);
$input = $formState
->getUserInput();
$schema = $input['schema'] ?? $server
->get('schema') ?: reset($schema_keys);
if ($this->operation == 'add') {
$form['#title'] = $this
->t('Add server');
}
else {
$form['#title'] = $this
->t('Edit %label server', [
'%label' => $server
->label(),
]);
}
$form['label'] = [
'#title' => $this
->t('Label'),
'#type' => 'textfield',
'#default_value' => $server
->label(),
'#description' => $this
->t('The human-readable name of this server.'),
'#required' => TRUE,
'#size' => 30,
];
$form['name'] = [
'#type' => 'machine_name',
'#default_value' => $server
->id(),
'#maxlength' => EntityTypeInterface::BUNDLE_MAX_LENGTH,
'#machine_name' => [
'exists' => [
'Drupal\\graphql\\Entity\\Server',
'load',
],
'source' => [
'label',
],
],
'#description' => $this
->t('A unique machine-readable name for this server. It must only contain lowercase letters, numbers, and underscores.'),
];
$form['schema'] = [
'#title' => $this
->t('Schema'),
'#type' => 'select',
'#options' => $schemas,
'#default_value' => $schema,
'#description' => $this
->t('The schema to use with this server.'),
'#ajax' => [
'callback' => '::ajaxSchemaConfigurationForm',
'progress' => [
'type' => 'throbber',
'message' => $this
->t('Updating schema configuration form.'),
],
],
];
$form['schema_configuration'] = [
'#type' => 'container',
'#prefix' => '<div id="edit-schema-configuration-plugin-wrapper">',
'#suffix' => '</div>',
'#tree' => TRUE,
];
$instance = $schema ? $this->schemaManager
->createInstance($schema) : NULL;
if ($instance instanceof PluginFormInterface && $instance instanceof ConfigurableInterface) {
$instance
->setConfiguration($server
->get('schema_configuration')[$schema] ?? []);
$form['schema_configuration'][$schema] = [
'#type' => 'fieldset',
'#title' => $this
->t('Schema configuration'),
'#tree' => TRUE,
];
$form['schema_configuration'][$schema] += $instance
->buildConfigurationForm([], $formState);
}
$form['endpoint'] = [
'#title' => $this
->t('Endpoint'),
'#type' => 'textfield',
'#default_value' => $server
->get('endpoint'),
'#description' => $this
->t('The endpoint for http queries. Has to start with a forward slash. For example "/graphql".'),
'#required' => TRUE,
'#size' => 30,
'#field_prefix' => $this->requestContext
->getCompleteBaseUrl(),
];
$form['batching'] = [
'#title' => $this
->t('Allow query batching'),
'#type' => 'checkbox',
'#default_value' => !!$server
->get('batching'),
'#description' => $this
->t('Whether batched queries are allowed.'),
];
$form['caching'] = [
'#title' => $this
->t('Enable caching'),
'#type' => 'checkbox',
'#default_value' => !!$server
->get('caching'),
'#description' => $this
->t('Whether caching of queries and partial results is enabled.'),
];
$debug_flags = $server
->get('debug_flag') ?? 0;
$form['debug_flag'] = [
'#title' => $this
->t('Debug settings'),
'#type' => 'checkboxes',
'#options' => [
DebugFlag::INCLUDE_DEBUG_MESSAGE => $this
->t("Add debugMessage key containing the exception message to errors."),
DebugFlag::INCLUDE_TRACE => $this
->t("Include the formatted original backtrace in errors."),
DebugFlag::RETHROW_INTERNAL_EXCEPTIONS => $this
->t("Rethrow the internal GraphQL exceptions"),
DebugFlag::RETHROW_UNSAFE_EXCEPTIONS => $this
->t("Rethrow unsafe GraphQL exceptions, these are exceptions that have not been marked as safe to expose to clients."),
],
'#default_value' => array_keys(array_filter([
DebugFlag::INCLUDE_DEBUG_MESSAGE => (bool) ($debug_flags & DebugFlag::INCLUDE_DEBUG_MESSAGE),
DebugFlag::INCLUDE_TRACE => (bool) ($debug_flags & DebugFlag::INCLUDE_TRACE),
DebugFlag::RETHROW_INTERNAL_EXCEPTIONS => (bool) ($debug_flags & DebugFlag::RETHROW_INTERNAL_EXCEPTIONS),
DebugFlag::RETHROW_UNSAFE_EXCEPTIONS => (bool) ($debug_flags & DebugFlag::RETHROW_UNSAFE_EXCEPTIONS),
])),
'#description' => $this
->t("It is recommended to disable all debugging in production. During development you can enable the information that you need above."),
];
$form['actions'] = [
'#type' => 'actions',
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this
->t('Submit'),
];
return $form;
}
public function validateForm(array &$form, FormStateInterface $formState) : void {
$endpoint =& $formState
->getValue('endpoint');
$endpoint = rtrim(trim(trim($endpoint), ''), "\\/");
if ($endpoint[0] !== '/') {
$formState
->setErrorByName('endpoint', 'The endpoint path has to start with a forward slash.');
}
elseif (!UrlHelper::isValid($endpoint)) {
$formState
->setErrorByName('endpoint', 'The endpoint path contains invalid characters.');
}
$schema = $formState
->getValue('schema');
$instance = $this->schemaManager
->createInstance($schema);
if (!empty($form['schema_configuration'][$schema]) && $instance instanceof PluginFormInterface && $instance instanceof ConfigurableInterface) {
$state = SubformState::createForSubform($form['schema_configuration'][$schema], $form, $formState);
$instance
->validateConfigurationForm($form['schema_configuration'][$schema], $state);
}
}
public function submitForm(array &$form, FormStateInterface $formState) : void {
$formState
->setValue('debug_flag', array_sum($formState
->getValue('debug_flag')));
parent::submitForm($form, $formState);
$schema = $formState
->getValue('schema');
$instance = $this->schemaManager
->createInstance($schema);
if ($instance instanceof PluginFormInterface && $instance instanceof ConfigurableInterface) {
$state = SubformState::createForSubform($form['schema_configuration'][$schema], $form, $formState);
$instance
->submitConfigurationForm($form['schema_configuration'][$schema], $state);
}
}
public function save(array $form, FormStateInterface $formState) {
$save_result = parent::save($form, $formState);
$this
->messenger()
->addMessage($this
->t('Saved the %label server.', [
'%label' => $this->entity
->label(),
]));
$formState
->setRedirect('entity.graphql_server.collection');
return $save_result;
}
}