View source
<?php
namespace Drupal\yamlform\Plugin\YamlFormHandler;
use Drupal\Core\Serialization\Yaml;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\yamlform\YamlFormHandlerBase;
use Drupal\yamlform\YamlFormSubmissionInterface;
use Drupal\yamlform\YamlFormTokenManagerInterface;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\RequestException;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
class RemotePostYamlFormHandler extends YamlFormHandlerBase {
protected $moduleHandler;
protected $httpClient;
protected $tokenManager;
public function __construct(array $configuration, $plugin_id, $plugin_definition, LoggerInterface $logger, ModuleHandlerInterface $module_handler, ClientInterface $http_client, YamlFormTokenManagerInterface $token_manager) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $logger);
$this->moduleHandler = $module_handler;
$this->httpClient = $http_client;
$this->tokenManager = $token_manager;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('logger.factory')
->get('yamlform.remote_post'), $container
->get('module_handler'), $container
->get('http_client'), $container
->get('yamlform.token_manager'));
}
public function getSummary() {
$configuration = $this
->getConfiguration();
if ($this
->getYamlForm()
->getSetting('results_disabled')) {
$configuration['settings']['update_url'] = '';
$configuration['settings']['delete_url'] = '';
}
return [
'#settings' => $configuration['settings'],
] + parent::getSummary();
}
public function defaultConfiguration() {
$field_names = array_keys(\Drupal::service('entity_field.manager')
->getBaseFieldDefinitions('yamlform_submission'));
$excluded_data = array_combine($field_names, $field_names);
return [
'type' => 'x-www-form-urlencoded',
'insert_url' => '',
'update_url' => '',
'delete_url' => '',
'excluded_data' => $excluded_data,
'custom_data' => '',
'insert_custom_data' => '',
'update_custom_data' => '',
'delete_custom_data' => '',
'debug' => FALSE,
];
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$yamlform = $this
->getYamlForm();
$results_disabled = $yamlform
->getSetting('results_disabled');
$form['insert_url'] = [
'#type' => 'url',
'#title' => $this
->t('Insert URL'),
'#description' => $this
->t('The full URL to POST to when a new form submission is saved. E.g. http://www.mycrm.com/form_insert_handler.php'),
'#required' => TRUE,
'#default_value' => $this->configuration['insert_url'],
];
$form['update_url'] = [
'#type' => 'url',
'#title' => $this
->t('Update URL'),
'#description' => $this
->t('The full URL to POST to when an existing form submission is updated. E.g. http://www.mycrm.com/form_insert_handler.php'),
'#default_value' => $this->configuration['update_url'],
'#access' => !$results_disabled,
];
$form['delete_url'] = [
'#type' => 'url',
'#title' => $this
->t('Save URL'),
'#description' => $this
->t('The full URL to POST to call when a form submission is deleted. E.g. http://www.mycrm.com/form_delete_handler.php'),
'#default_value' => $this->configuration['delete_url'],
'#access' => !$results_disabled,
];
$form['type'] = [
'#type' => 'select',
'#title' => $this
->t('Post type'),
'#description' => $this
->t('Use x-www-form-urlencoded if unsure, as it is the default format for HTML forms. You also have the option to post data in <a href="http://www.json.org/" target="_blank">JSON</a> format.'),
'#options' => [
'x-www-form-urlencoded' => $this
->t('x-www-form-urlencoded'),
'json' => $this
->t('JSON'),
],
'#required' => TRUE,
'#default_value' => $this->configuration['type'],
];
$form['submission_data'] = [
'#type' => 'details',
'#title' => $this
->t('Submission data'),
];
$form['submission_data']['excluded_data'] = [
'#type' => 'yamlform_excluded_columns',
'#title' => $this
->t('Posted data'),
'#title_display' => 'invisible',
'#yamlform' => $yamlform,
'#required' => TRUE,
'#parents' => [
'settings',
'excluded_data',
],
'#default_value' => $this->configuration['excluded_data'],
];
$form['custom_data'] = [
'#type' => 'details',
'#title' => $this
->t('Custom data'),
'#description' => $this
->t('Custom data will take precedence over submission data. You may use tokens.'),
];
$form['custom_data']['custom_data'] = [
'#type' => 'yamlform_codemirror',
'#mode' => 'yaml',
'#title' => $this
->t('Custom data'),
'#description' => $this
->t('Enter custom data that will be included in all remote post requests.'),
'#parents' => [
'settings',
'custom_data',
],
'#default_value' => $this->configuration['custom_data'],
];
$form['custom_data']['insert_custom_data'] = [
'#type' => 'yamlform_codemirror',
'#mode' => 'yaml',
'#title' => $this
->t('Insert data'),
'#description' => $this
->t("Enter custom data that will be included when a new form submission is saved."),
'#parents' => [
'settings',
'insert_custom_data',
],
'#states' => [
'visible' => [
[
':input[name="settings[update_url]"]' => [
'filled' => TRUE,
],
],
'or',
[
':input[name="settings[delete_url]"]' => [
'filled' => TRUE,
],
],
],
],
'#default_value' => $this->configuration['insert_custom_data'],
];
$form['custom_data']['update_custom_data'] = [
'#type' => 'yamlform_codemirror',
'#mode' => 'yaml',
'#title' => $this
->t('Update data'),
'#description' => $this
->t("Enter custom data that will be included when a form submission is updated."),
'#parents' => [
'settings',
'update_custom_data',
],
'#states' => [
'visible' => [
':input[name="settings[update_url]"]' => [
'filled' => TRUE,
],
],
],
'#default_value' => $this->configuration['update_custom_data'],
];
$form['custom_data']['delete_custom_data'] = [
'#type' => 'yamlform_codemirror',
'#mode' => 'yaml',
'#title' => $this
->t('Delete data'),
'#description' => $this
->t("Enter custom data that will be included when a form submission is deleted."),
'#parents' => [
'settings',
'delete_custom_data',
],
'#states' => [
'visible' => [
':input[name="settings[delete_url]"]' => [
'filled' => TRUE,
],
],
],
'#default_value' => $this->configuration['delete_custom_data'],
];
$form['custom_data']['token_tree_link'] = $this->tokenManager
->buildTreeLink();
$form['debug'] = [
'#type' => 'checkbox',
'#title' => $this
->t('Enable debugging'),
'#description' => $this
->t('If checked, posted submissions will be displayed onscreen to all users.'),
'#return_value' => TRUE,
'#default_value' => $this->configuration['debug'],
];
return $form;
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
$values = $form_state
->getValues();
foreach ($this->configuration as $name => $value) {
if (isset($values[$name])) {
$this->configuration[$name] = $values[$name];
}
}
}
public function postSave(YamlFormSubmissionInterface $yamlform_submission, $update = TRUE) {
$operation = $update ? 'update' : 'insert';
$this
->remotePost($operation, $yamlform_submission);
}
public function postDelete(YamlFormSubmissionInterface $yamlform_submission) {
$this
->remotePost('delete', $yamlform_submission);
}
protected function remotePost($operation, YamlFormSubmissionInterface $yamlform_submission) {
$request_url = $this->configuration[$operation . '_url'];
if (empty($request_url)) {
return;
}
$request_type = $this->configuration['type'];
$request_post_data = $this
->getPostData($operation, $yamlform_submission);
try {
switch ($request_type) {
case 'json':
$response = $this->httpClient
->post($request_url, [
'json' => $request_post_data,
]);
break;
case 'x-www-form-urlencoded':
default:
$response = $this->httpClient
->post($request_url, [
'form_params' => $request_post_data,
]);
break;
}
} catch (RequestException $request_exception) {
$message = $request_exception
->getMessage();
$response = $request_exception
->getResponse();
$this
->debug($message, $operation, $request_url, $request_type, $request_post_data, $response, 'error');
$context = [
'@form' => $this
->getYamlForm()
->label(),
'@operation' => $operation,
'@type' => $request_type,
'@url' => $request_url,
'@message' => $message,
'link' => $this
->getYamlForm()
->toLink(t('Edit'), 'handlers-form')
->toString(),
];
$this->logger
->error('@form form remote @type post (@operation) to @url failed. @message', $context);
return;
}
$this
->debug(t('Remote post successful!'), $operation, $request_url, $request_type, $request_post_data, $response, 'warning');
}
protected function getPostData($operation, YamlFormSubmissionInterface $yamlform_submission) {
$data = $yamlform_submission
->toArray(TRUE);
$data = $data['data'] + $data;
unset($data['data']);
$data = array_diff_key($data, $this->configuration['excluded_data']);
if (!empty($this->configuration['custom_data'])) {
$data = Yaml::decode($this->configuration['custom_data']) + $data;
}
if (!empty($this->configuration[$operation . '_custom_data'])) {
$data = Yaml::decode($this->configuration[$operation . '_custom_data']) + $data;
}
$data = $this->tokenManager
->replace($data, $yamlform_submission);
return $data;
}
protected function debug($message, $operation, $request_url, $request_type, $request_post_data, ResponseInterface $response = NULL, $type = 'warning') {
if (empty($this->configuration['debug'])) {
return;
}
$build = [];
$build['message'] = [
'#markup' => $message,
'#prefix' => '<b>',
'#suffix' => '</b>',
];
$build['operation'] = [
'#type' => 'item',
'#title' => $this
->t('Remote operation'),
'#markup' => $operation,
];
$build['request_url'] = [
'#type' => 'item',
'#title' => $this
->t('Request URL'),
'#markup' => $request_url,
];
$build['request_type'] = [
'#type' => 'item',
'#title' => $this
->t('Request type'),
'#markup' => $request_type,
];
$build['request_post_data'] = [
'#type' => 'item',
'#title' => $this
->t('Request data'),
'data' => [
'#markup' => htmlspecialchars(Yaml::encode($request_post_data)),
'#prefix' => '<pre>',
'#suffix' => '</pre>',
],
];
$build['returned'] = [
'#markup' => $this
->t('...returned...'),
'#prefix' => '<b>',
'#suffix' => '</b>',
];
if ($response) {
$build['response_code'] = [
'#type' => 'item',
'#title' => $this
->t('Response status code'),
'#markup' => $response
->getStatusCode(),
];
$build['response_header'] = [
'#type' => 'details',
'#title' => $this
->t('Response header'),
'data' => [
'#markup' => htmlspecialchars(Yaml::encode($response
->getHeaders())),
'#prefix' => '<pre>',
'#suffix' => '</pre>',
],
];
$build['response_body'] = [
'#type' => 'details',
'#title' => $this
->t('Response body'),
'data' => [
'#markup' => htmlspecialchars($response
->getBody()),
'#prefix' => '<pre>',
'#suffix' => '</pre>',
],
];
}
else {
$build['response_code'] = [
'#markup' => t('No response. Please see the recent log messages.'),
'#prefix' => '<p>',
'#suffix' => '</p>',
];
}
drupal_set_message(\Drupal::service('renderer')
->renderPlain($build), $type);
}
}