array( 'title' => t('Administer all forms'), 'restrict access' => TRUE, ), 'view all forms submissions' => array( 'title' => t('View all forms submissions'), 'restrict access' => TRUE, ), 'edit all forms submissions' => array( 'title' => t('Edit all forms submissions'), 'restrict access' => TRUE, ), 'delete all forms submissions' => array( 'title' => t('Delete all forms submissions'), 'restrict access' => TRUE, ), ); } /** * Implements hook_menu(). */ function forms_menu() { $items = array(); // Front end section. $items['form/%forms'] = array( 'page callback' => 'forms_submission_edit', 'page arguments' => array(1, NULL), 'access callback' => 'forms_submission_access_callback', 'access arguments' => array(1), 'file' => 'forms_submission.pages.inc', 'title callback' => 'forms_page_title', 'title arguments' => array(1), ); $items['form/%forms/form'] = array( 'title' => 'Form', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); // Submissions. $items['form/%forms/submission/%forms_submission'] = array( 'page callback' => 'forms_submission_page_view', 'page arguments' => array(1, 3), 'access arguments' => array('view all forms submissions'), 'file' => 'forms_submission.pages.inc', 'title callback' => 'forms_page_title', 'title arguments' => array(1, 'Submission for form @form_name'), ); $items['form/%forms/submission/%forms_submission/view'] = array( 'title' => 'View', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items['form/%forms/submission/%forms_submission/edit'] = array( 'title' => 'Edit', 'page callback' => 'forms_submission_edit', 'page arguments' => array(1, 3), 'access arguments' => array('edit all forms submissions'), 'type' => MENU_LOCAL_TASK, 'file' => 'forms_submission.pages.inc', ); $items['form/%forms/submission/%forms_submission/delete'] = array( 'title' => 'Delete', 'page callback' => 'drupal_get_form', 'page arguments' => array('forms_submission_delete_confirm', 1, 3), 'access arguments' => array('delete all forms submissions'), 'type' => MENU_LOCAL_TASK, 'weight' => 10, 'file' => 'forms_submission.pages.inc', ); // Submission overview. $items['form/%forms/submissions'] = array( 'page callback' => 'forms_submission_list_view', 'page arguments' => array(1), 'access arguments' => array('view all forms submissions'), 'file' => 'forms.admin.inc', 'title' => 'Submissions', 'type' => MENU_LOCAL_TASK, 'weight' => 10, ); // Edit. $items['form/%forms/edit/form'] = array( 'title' => 'Settings', 'description' => 'Edit basic form settings', 'page callback' => 'drupal_get_form', 'page arguments' => array('forms_form', 1), 'access arguments' => array('administer forms'), 'file' => 'forms.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 100, ); // Delete. $items['form/%forms/delete'] = array( 'title' => 'Delete', 'description' => 'Delete a form', 'page callback' => 'drupal_get_form', 'page arguments' => array('forms_delete_confirm', 1), 'access arguments' => array('administer forms'), 'file' => 'forms.admin.inc', 'type' => MENU_LOCAL_TASK, 'weight' => 100, ); // Admin section. $items['admin/structure/forms'] = array( 'title' => 'Forms', 'description' => 'Manage frontend forms.', 'page callback' => 'forms_overview', 'access arguments' => array('administer forms'), 'file' => 'forms.admin.inc', ); $items['admin/structure/forms/list'] = array( 'title' => 'List', 'description' => 'Manage frontend forms.', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); $items['admin/structure/forms/add'] = array( 'title' => 'Add a form', 'description' => 'Add a form.', 'page callback' => 'drupal_get_form', 'page arguments' => array('forms_form'), 'access arguments' => array('administer forms'), 'type' => MENU_LOCAL_ACTION, 'file' => 'forms.admin.inc', ); return $items; } /** * Implements hook_menu_alter. */ function forms_menu_alter(&$items) { if (isset($items['form/%forms/edit/fields'])) { $items['form/%forms/edit'] = $items['form/%forms/edit/fields']; $items['form/%forms/edit/fields'] = array( 'title' => $items['form/%forms/edit']['title'], 'type' => MENU_DEFAULT_LOCAL_TASK, ); $items['form/%forms/edit']['title'] = 'Edit'; $items['form/%forms/edit']['weight'] = 20; } } /** * Implements hook_theme(). */ function forms_theme() { return array( 'forms_admin_overview' => array( 'variables' => array('forms' => NULL), ), ); } /** * Implements hook_preprocess_page. * * TODO: find a better way to display tabs on the 3rd level. * It is now pushed in the $content of the page. */ function forms_preprocess_page(&$vars) { if (arg(0) == 'form' && arg(2) == 'edit') { $tabs = menu_local_tasks(2); if ($tabs['tabs']['count'] > 1) { drupal_add_css(drupal_get_path('module', 'forms') . '/forms.css'); $vars['page']['content']['system_main']['forms_tabs_tertiary'] = $tabs['tabs']['output']; $vars['page']['content']['system_main']['forms_tabs_tertiary']['#weight'] = -150; $vars['page']['content']['system_main']['forms_tabs_tertiary']['#prefix'] = '
'; } } } /** * Implements hook_admin_paths_alter. */ function forms_admin_paths_alter(&$paths) { $paths['form/*/edit'] = TRUE; $paths['form/*/edit/*'] = TRUE; $paths['form/*/delete'] = TRUE; } /** * Access callback. Are we allowed to submit against a forms? */ function forms_submission_access_callback($forms) { $access = FALSE; if ($forms->page <> 0 && $forms->submissions) { $access = TRUE; } if (!$access && (user_access('administer forms') || user_access('edit all forms submissions'))) { $access = TRUE; } return $access; } /** * Implements hook_entity_info(). */ function forms_entity_info() { $entity = array( 'forms_submission' => array( 'label' => t('Forms submission'), 'base table' => 'forms_submission', 'revision table' => 'forms_submission_revision', 'uri callback' => 'forms_submission_uri', 'load hook' => 'form_submission_load', 'fieldable' => TRUE, 'entity keys' => array( 'id' => 'fssid', 'revision' => 'fsvid', 'bundle' => 'form', 'label' => 'name', ), 'bundle keys' => array( 'bundle' => 'form', ), 'bundles' => array(), 'view modes' => array( 'form_submission' => array( 'label' => t('Forms submission'), 'custom settings' => FALSE, ), 'submissions_overview' => array( 'label' => t('Submissions overview'), 'custom settings' => FALSE, ), ), ), ); foreach (forms_info() as $form_name => $forms) { $entity['forms_submission']['bundles'][$form_name] = array( 'label' => $forms->name, 'admin' => array( 'path' => 'form/%forms/edit', 'real path' => 'form/' . str_replace('_', '-', $form_name) . '/edit', 'bundle argument' => 1, 'access arguments' => array('administer forms'), ), ); } return $entity; } /** * Implements hook_field_extra_fields. */ function forms_field_extra_fields() { $extra = array(); foreach (forms_info() as $form_name => $forms) { $extra['forms_submission'][$form_name] = array( 'display' => array( 'ip_address' => array( 'label' => t('IP address'), 'description' => t('The IP address'), 'weight' => 50, ), 'submitted' => array( 'label' => t('Submitted'), 'description' => t('The timestamp of the first submission'), 'weight' => 50, 'entity_property' => 'created', ), 'changed' => array( 'label' => t('Changed'), 'description' => t('The timestamp of the last change on the submission'), 'weight' => 50, 'entity_property' => 'changed', ), ), ); } return $extra; } /** * Implements hook_forms_submission_view. * * Attach the display of extra fields. */ function forms_forms_submission_view($entity, $view_mode, $langcode) { $entity->build['ip_address'] = array( '#view_mode' => $view_mode, '#field_language' => LANGUAGE_NONE, '#field_translatable' => FALSE, '#field_name' => 'ip_address', '#field_type' => 'pseudo', '#label_display' => 'inline', '#title' => t('IP address'), '#entity_type' => 'forms_submission', '#bundle' => $entity->form, '#items' => array(array( 'value' => $entity->remote_addr, 'safe_value' => check_plain($entity->remote_addr), )), '#theme' => 'field', 0 => array( '#markup' => check_plain($entity->remote_addr), ), ); $entity->build['submitted'] = array( '#view_mode' => $view_mode, '#field_language' => LANGUAGE_NONE, '#field_translatable' => FALSE, '#field_name' => 'submitted', '#field_type' => 'pseudo', '#label_display' => 'inline', '#title' => t('Submitted'), '#entity_type' => 'forms_submission', '#bundle' => $entity->form, '#items' => array(array( 'value' => $entity->created, 'safe_value' => format_date($entity->created, 'short'), )), '#theme' => 'field', 0 => array( '#markup' => format_date($entity->created, 'short'), ), ); $entity->build['changed'] = array( '#view_mode' => $view_mode, '#field_language' => LANGUAGE_NONE, '#field_translatable' => FALSE, '#field_name' => 'submitted', '#field_type' => 'pseudo', '#label_display' => 'inline', '#title' => t('Changed'), '#entity_type' => 'forms_submission', '#bundle' => $entity->form, '#items' => array(array( 'value' => $entity->created, 'safe_value' => format_date($entity->changed, 'short'), )), '#theme' => 'field', 0 => array( '#markup' => format_date($entity->changed, 'short'), ), ); } /** * Get the uri for a forms submission. */ function forms_submission_uri($forms_submission) { $forms_url_str = str_replace('_', '-', $forms_submission->form); return array( 'path' => 'form/' . $forms_url_str . '/submission/' . $forms_submission->fssid, ); } /* * Saves a forms_submission. */ function forms_submission_save($forms_submission) { $transaction = db_transaction(); try { // Load the stored entity, if any. if (!empty($forms_submission->fssid) && !isset($forms_submission->original)) { $forms_submission->original = entity_load_unchanged('forms_submission', $forms_submission->fssid); } field_attach_presave('forms_submission', $forms_submission); global $user; // Determine if we will be inserting a new submission. if (!isset($forms_submission->is_new)) { $forms_submission->is_new = empty($forms_submission->fssid); } // Set the timestamp fields. if (empty($forms_submission->created)) { $forms_submission->created = REQUEST_TIME; } // The changed timestamp is always updated for bookkeeping purposes, // for example: revisions, searching, etc. $forms_submission->changed = REQUEST_TIME; $forms_submission->timestamp = REQUEST_TIME; $forms_submission->remote_addr = ip_address(); $update = TRUE; // Let modules modify the submission before it is saved to the database. module_invoke_all('forms_submission_presave', $forms_submission); module_invoke_all('entity_presave', $forms_submission, 'forms_submission'); if (!$forms_submission->is_new) { $forms_submission->old_fsvid = $forms_submission->fsvid; unset($forms_submission->fsvid); } // Save. drupal_write_record('forms_submission_revision', $forms_submission); if ($forms_submission->is_new) { drupal_write_record('forms_submission', $forms_submission); $op = 'insert'; // resave to save the fssid. drupal_write_record('forms_submission_revision', $forms_submission, 'fsvid'); } else { drupal_write_record('forms_submission', $forms_submission, 'fssid'); $op = 'update'; } // Save fields. $function = "field_attach_$op"; $function('forms_submission', $forms_submission); module_invoke_all('forms_submission_' . $op, $forms_submission); module_invoke_all('entity_' . $op, $forms_submission, 'forms_submission'); // Clear internal properties. unset($forms_submission->is_new); unset($forms_submission->original); // Clear the static loading cache. entity_get_controller('forms_submission')->resetCache(array($forms_submission->fssid)); db_ignore_slave(); } catch (Exception $e) { $transaction->rollback(); watchdog_exception('forms_submission', $e); throw $e; } } /** * Menu argument loader: loads a forms_submission by fssid. */ function forms_submission_load($fssid, $reset = FALSE) { $forms = forms_submission_load_multiple(array($fssid), array(), $reset); return reset($forms); } /** * Loads multiple entities of the type forms_submission. */ function forms_submission_load_multiple($fssids = array(), $conditions = array(), $reset = FALSE) { return entity_load('forms_submission', $fssids, $conditions, $reset); } /** * Delete a forms submission. */ function forms_submission_delete($fssid) { forms_submission_delete_multiple(array($fssid)); } /** * Delete multiple forms submissions. */ function forms_submission_delete_multiple($fssids) { $transaction = db_transaction(); if (!empty($fssids)) { $forms_submissions = forms_submission_load_multiple($fssids); try { foreach ($forms_submissions as $fssid => $forms_submission) { module_invoke_all('forms_submission_delete', $forms_submission); module_invoke_all('entity_delete', $forms_submission, 'forms_submission'); field_attach_delete('forms_submission', $forms_submission); } db_delete('forms_submission') ->condition('fssid', $fssids, 'IN') ->execute(); db_delete('forms_submission_revision') ->condition('fssid', $fssids, 'IN') ->execute(); } catch (Exception $e) { $transaction->rollback(); watchdog_exception('forms_submission', $e); throw $e; } entity_get_controller('forms_submission')->resetCache(); } } /** * Menu argument loader: loads a forms by string. * * @param $name * The machine-readable name of a form to load. * * @return $forms * A form object or FALSE if $form does not exist. */ function forms_load($form_name) { return forms_info(strtr($form_name, array('-' => '_'))); } /** * Finds all forms objects optionally filtered. */ function forms_info($form_name = NULL) { $forms = &drupal_static(__FUNCTION__); if (empty($forms)) { $forms = array(); $query = db_select('forms', 'f') ->fields('f') ->orderBy('f.form', 'ASC') ->execute(); foreach ($query as $forms_object) { $forms[$forms_object->form] = $forms_object; $forms[$forms_object->form]->settings = unserialize($forms[$forms_object->form]->settings); } } if (!empty ($form_name)) { return (isset($forms[$form_name])) ? $forms[$form_name] : FALSE; } return $forms; } /** * Save forms object. Fires hook_forms_update or hook_forms_insert. * * @return $status * Contains a constant SAVED_UPDATED or SAVED_NEW. */ function forms_save($info) { $is_existing = FALSE; $existing_form = !empty($info->old_form) ? $info->old_form : $info->form; $is_existing = (bool) db_query_range('SELECT 1 FROM {forms} WHERE form = :form', 0, 1, array(':form' => $existing_form))->fetchField(); $forms = forms_set_defaults($info); $fields = array( 'form' => (string) $forms->form, 'name' => (string) $forms->name, 'description' => (string) $forms->description, 'module' => $forms->module, 'page' => $forms->page, 'block' => $forms->block, 'submissions' => $forms->submissions, 'settings' => serialize($forms->settings), ); if ($is_existing) { db_update('forms') ->fields($fields) ->condition('form', $existing_form) ->execute(); if (!empty($forms->old_form) && $forms->old_form != $forms->form) { field_attach_rename_bundle('forms_submission', $forms->old_form, $forms->form); } module_invoke_all('forms_update', $forms); $status = SAVED_UPDATED; } else { db_insert('forms') ->fields($fields) ->execute(); field_attach_create_bundle('forms_submission', $forms->form); module_invoke_all('forms_insert', $forms); $status = SAVED_NEW; } return $status; } /** * Delete forms object. Fires hook_forms_delete. */ function forms_delete($form) { $forms = forms_load($form); db_delete('forms') ->condition('form', $forms->form) ->execute(); field_attach_delete_bundle('forms_submission', $forms->form); module_invoke_all('forms_delete', $forms); } /** * Set defaults for a forms object. */ function forms_set_defaults($info = array()) { $info = (array) $info; $new_forms = $info + array( 'form' => '', 'name' => '', 'description' => '', 'page' => 1, 'block' => 0, 'submissions' => 1, 'settings' => array( 'submit_label' => 'Submit', 'after_submit' => 'display', 'redirect_url' => '', 'confirmation_message' => 'Thank you. Your submission is saved.', 'display_message' => 'system', ), ); $new_forms = (object) $new_forms; if (empty($new_forms->module)) { $new_forms->module = 'forms'; } $new_forms->orig_form = isset($info['form']) ? $info['form'] : ''; return $new_forms; } /** * Implements hook_forms(). * * All forms forms share the same form handler. */ function forms_forms($form_id, $args) { $forms = array(); if ($forms_arr = forms_info()) { foreach (array_keys($forms_arr) as $form_name) { $forms[$form_name . '_forms_submission_form']['callback'] = 'forms_submission_form'; $forms[$form_name . '_block_forms_submission_form']['callback'] = 'forms_submission_form'; } } return $forms; } /** * Title callback. */ function forms_page_title($forms, $string = NULL) { if (empty($string)) { $string = '@form_name'; } return t($string, array('@form_name' => $forms->name)); } /** * Implements hook_views_api(). */ function forms_views_api() { return array( 'api' => 3.0, 'path' => drupal_get_path('module', 'forms') . '/views', ); } /** * Implements hook_features_api(). * * Main info hook that features uses to determine what components are provided * by the implementing module. */ function forms_features_api() { return array( 'forms' => array( 'name' => t('Forms'), 'feature_source' => TRUE, 'default_hook' => 'forms_defaults', 'file' => drupal_get_path('module', 'forms') . '/features/forms.features.inc', ), ); } /** * Trigger events with the provided hooks in forms for rules. */ if (module_exists('rules')) { /** * Implements hook_forms_submission_insert(). */ function forms_forms_submission_insert($forms_submission) { rules_invoke_event('forms_submission_insert', $forms_submission); } /** * Implements hook_forms_submission_update(). */ function forms_forms_submission_update($forms_submission) { rules_invoke_event('forms_submission_update', $forms_submission); } /** * Implements hook_forms_submission_presave(). */ function forms_forms_submission_presave($forms_submission) { rules_invoke_event('forms_submission_presave', $forms_submission); } /** * Implements hook_forms_submission_delete(). */ function forms_forms_submission_delete($forms_submission) { rules_invoke_event('forms_submission_delete', $forms_submission); } } /** * Implements hook_block_info(). */ function forms_block_info() { $blocks = array(); foreach(forms_info() as $forms_name => $forms) { if ($forms->block) { $blocks['forms_' . $forms_name] = array( 'info' => t('Form: @forms', array('@forms' => $forms->name)), 'cache' => DRUPAL_NO_CACHE, ); } } return $blocks; } /** * Implements hook_block_view(). */ function forms_block_view($delta = '') { global $user; list ($type, $form_name) = explode('_', $delta); if ($type == 'forms' && !empty($form_name)) { $forms = forms_info($form_name); if ($forms->submissions) { module_load_include('inc', 'forms', 'forms_submission.pages'); $forms_submission = (object) array( 'uid' => $user->uid, 'form' => $forms->form, 'submit_label' => $forms->settings['submit_label'], ); return array( 'subject' => t($forms->name), 'content' => drupal_get_form($forms->form . '_block_forms_submission_form', $forms, $forms_submission), ); } } }