webform_share.module in Webform share 7
Same filename and directory in other branches
Module to handle importing and exporting of webforms, as well as adding the ability to set content type defaults.
File
webform_share.moduleView source
<?php
/**
* @file
* Module to handle importing and exporting of webforms, as well as adding the
* ability to set content type defaults.
*/
/**
* Implements hook_permission().
* This is required as we are handling PHP based files on import / export.
*/
function webform_share_permission() {
return array(
'access webform share functionality' => array(
'title' => t('Configure Webform Share'),
'description' => t('This permission enables the user to paste and run PHP code on the server.'),
'restrict access' => TRUE,
),
);
}
/**
* Helper function to get the content type defaults.
*/
function webform_share_node_type_defaults($type) {
if (in_array($type, webform_variable_get('webform_node_types'))) {
return variable_get('webform_share_' . $type, '');
}
return '';
}
/**
* Implements hook_menu().
*/
function webform_share_menu() {
$items = array();
$items['node/%webform_menu/webform/ws-export'] = array(
'title' => 'Export',
'page callback' => 'webform_share_export',
'page arguments' => array(
1,
),
'access callback' => 'node_access',
'access arguments' => array(
'update',
1,
),
'weight' => 5,
'type' => MENU_LOCAL_TASK,
);
$items['node/%webform_menu/webform/ws-import'] = array(
'title' => 'Import',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'webform_share_components_update_form',
1,
),
'access callback' => 'webform_share_menu_access',
'access arguments' => array(
1,
),
'weight' => 6,
'type' => MENU_LOCAL_TASK,
);
$items['node/%webform_menu/webform/ws-reset'] = array(
'title' => 'Reset',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'webform_share_components_update_form',
1,
TRUE,
),
'access callback' => 'webform_share_menu_access',
'access arguments' => array(
1,
'reset',
),
'weight' => 7,
'type' => MENU_LOCAL_TASK,
);
return $items;
}
/**
* Menu access callback.
* Custom check on both the user access and node access.
*/
function webform_share_menu_access($node, $reset = FALSE) {
if (node_access('update', $node)) {
// We can only reset if there is some defaults set.
if ($reset && !webform_share_node_type_defaults($node->type)) {
return FALSE;
}
return user_access('access webform share functionality');
}
return FALSE;
}
/**
* This form is used to update or to reset the webform.
*/
function webform_share_components_update_form($form, &$form_state, $node, $op = 'import') {
$form_state['node'] = $node;
$form['components_only'] = array(
'#type' => 'checkbox',
'#title' => t('Update components only'),
'#default_value' => 1,
'#description' => t('If unchecked, the roles, emails and other settings will be overridden.'),
);
$form['keep_existing_components'] = array(
'#type' => 'checkbox',
'#title' => t('Keep existing components that are not included in the import'),
'#default_value' => 1,
'#description' => t('If unchecked, the existing components that do not map to an imported webform form_key will be deleted. All submission data associated with those components will be lost.'),
);
$form['import'] = array(
'#type' => 'textarea',
'#title' => t('Import code'),
'#default_value' => '',
'#description' => t('Copy the code that was generated from a webform share export. This should not include <?PHP or ?> tags.'),
'#required' => TRUE,
);
if ($op == 'reset') {
$form['import']['#access'] = FALSE;
$form['import']['#default_value'] = variable_get('webform_share_' . $node->type, '');
}
$form['submit'] = array(
'#type' => 'submit',
'#value' => $op == 'reset' ? t('Reset') : t('Import'),
);
return $form;
}
/**
* Submit callback to update the node.
*/
function webform_share_components_update_form_submit($form, &$form_state) {
$node = $form_state['node'];
if ($webform = _webform_share_eval($form_state['values']['import'])) {
$hook_params = array(
'operation' => 'update',
'node' => $node,
'options' => array(
'components_only' => $form_state['values']['components_only'],
'keep_existing_components' => $form_state['values']['keep_existing_components'],
),
);
drupal_alter('webform_share_import', $webform, $hook_params);
// Load the original node and use this to map any fields based off
// the form_key parameter. We need to preserve the existing cid if
// possible to preserve the submission data.
$original = node_load($node->nid, NULL, TRUE);
$existing_components = array();
foreach ($original->webform['components'] as $cid => $component) {
$existing_components[$component['form_key']] = $cid;
}
// Get the max cid for this node's webform so we know where our safe
// starting point is.
$current_max_cid = webform_share_get_next_max_cid($node->nid);
// Overwrite the entire form if the user is updating everything.
if (empty($form_state['values']['components_only'])) {
$node->webform = $webform;
$webform['nid'] = $node->nid;
}
$old_to_new_mappings = array();
// Map the imported components to the existing webform components.
$node->webform['components'] = array();
foreach ($webform['components'] as $index => $component) {
if (isset($existing_components[$component['form_key']])) {
$cid = $existing_components[$component['form_key']];
unset($existing_components[$component['form_key']]);
}
else {
$cid = ++$current_max_cid;
}
$old_to_new_mappings[$component['cid']] = $cid;
if (!empty($component['pid'])) {
// This mapping assumes that parents always come before children.
if (empty($old_to_new_mappings[$component['pid']])) {
drupal_set_message(t('Unable to find the correct fieldset for %component.', array(
'%component' => $component['name'],
)), 'error', TRUE);
}
else {
$component['pid'] = $old_to_new_mappings[$component['pid']];
}
}
// Set the new cid.
$component['cid'] = $cid;
$component['nid'] = $node->nid;
$node->webform['components'][$cid] = $component;
}
// Map the imported conditionals.
$webform['conditionals'] = isset($webform['conditionals']) ? $webform['conditionals'] : array();
foreach ($webform['conditionals'] as $index => $conditional) {
foreach ($conditional['rules'] as $rindex => $rule) {
if (isset($rule['source']) && $rule['source'] != NULL) {
$rule['nid'] = $node->nid;
if (!empty($old_to_new_mappings[$rule['source']])) {
$rule['source'] = $old_to_new_mappings[$rule['source']];
}
else {
drupal_set_message(t('Unable to find the correct sources for conditionals.'), 'error', FALSE);
}
$conditional['rules'][$rindex] = $rule;
}
}
foreach ($conditional['actions'] as $aindex => $action) {
if (isset($action['target']) && $action['target'] != NULL) {
$action['nid'] = $node->nid;
if (!empty($old_to_new_mappings[$action['target']])) {
$action['target'] = $old_to_new_mappings[$action['target']];
}
else {
drupal_set_message(t('Unable to find the correct targets for conditionals.'), 'error', FALSE);
}
$conditional['actions'][$aindex] = $action;
}
}
$node->webform['conditionals'][$index] = $conditional;
}
// If requested, re-add the existing components rather than allowing these
// to be deleted. Existing cid values are safe to reuse.
if (!empty($form_state['values']['keep_existing_components'])) {
foreach ($existing_components as $form_key => $cid) {
$node->webform['components'][$cid] = $original->webform['components'][$cid];
}
}
if (isset($node->webform['emails'])) {
foreach ($node->webform['emails'] as $index => $component) {
$node->webform['emails'][$index]['nid'] = $node->nid;
}
}
node_save($node);
}
$form_state['redirect'] = 'node/' . $node->nid . '/webform';
}
/**
* Retrieves that last "cid" for a node's webform.
*
* @param int $nid
* @return int
*/
function webform_share_get_next_max_cid($nid) {
$max_cid = db_select('webform_component', 'w')
->fields('w', array(
'cid',
))
->condition('nid', $nid)
->orderBy('cid', 'DESC')
->range(0, 1)
->execute()
->fetchField();
return empty($max_cid) ? 0 : $max_cid;
}
/**
* Menu callback to generate the webform dump.
*/
function webform_share_export($node) {
drupal_alter('webform_share_export', $node);
$webform = '$webform = ' . var_export($node->webform, TRUE) . ";\n\n";
if (ob_get_level()) {
ob_end_clean();
}
drupal_add_http_header('Content-Type', 'text/plain; charset=utf-8');
drupal_add_http_header('Content-Disposition', 'attachment; filename="webform-' . $node->type . '-' . $node->nid . '.txt";');
drupal_add_http_header('Content-Length', sprintf('%u', strlen($webform)));
print $webform;
exit;
}
/**
* This hooks into the node type form to add the webform share default settings
* textarea.
*/
function webform_share_form_node_type_form_alter(&$form, $form_state) {
// Targets content type edit forms
if (isset($form['#node_type'])) {
// Only adds the element to content types that have been tag for webforms.
if (in_array($form['#node_type']->type, webform_variable_get('webform_node_types'))) {
// Make sure that the user has permission.
if (user_access('access webform share functionality')) {
$form['workflow']['webform_share'] = array(
'#type' => 'textarea',
'#title' => t('Web form default components'),
'#default_value' => variable_get('webform_share_' . $form['#node_type']->type, ''),
// Access PHP so we need to control this.
'#access' => user_access('access webform share functionality'),
'#description' => t('Copy the code that was generated from a webform share export. This should not include <?PHP or ?> tags.'),
);
}
}
}
}
/**
* Implements hook_node_insert().
*/
function webform_share_node_insert($node) {
if ($type_defaults = webform_share_node_type_defaults($node->type)) {
if ($webform = _webform_share_eval($type_defaults)) {
$hook_params = array(
'operation' => 'insert',
'node' => $node,
'options' => array(
'components_only' => FALSE,
'keep_existing_components' => FALSE,
),
);
drupal_alter('webform_share_import', $webform, $hook_params);
$node->webform = $webform;
$node->webform['nid'] = $node->nid;
if (isset($node->webform['components'])) {
$node->webform['components'] = array_filter((array) $node->webform['components']);
foreach ($node->webform['components'] as $index => $component) {
$node->webform['components'][$index]['nid'] = $node->nid;
}
}
if (isset($node->webform['emails'])) {
foreach ($node->webform['emails'] as $index => $email) {
$node->webform['emails'][$index]['nid'] = $node->nid;
}
}
}
}
}
/**
* Private helper function to assist in getting the information from the
* webform dump.
*/
function _webform_share_eval($str) {
eval($str);
return empty($webform) ? FALSE : $webform;
}
Functions
Name![]() |
Description |
---|---|
webform_share_components_update_form | This form is used to update or to reset the webform. |
webform_share_components_update_form_submit | Submit callback to update the node. |
webform_share_export | Menu callback to generate the webform dump. |
webform_share_form_node_type_form_alter | This hooks into the node type form to add the webform share default settings textarea. |
webform_share_get_next_max_cid | Retrieves that last "cid" for a node's webform. |
webform_share_menu | Implements hook_menu(). |
webform_share_menu_access | Menu access callback. Custom check on both the user access and node access. |
webform_share_node_insert | Implements hook_node_insert(). |
webform_share_node_type_defaults | Helper function to get the content type defaults. |
webform_share_permission | Implements hook_permission(). This is required as we are handling PHP based files on import / export. |
_webform_share_eval | Private helper function to assist in getting the information from the webform dump. |