$form) {
$status = $form['source'];
$delete = t('delete');
$edit = l(t('edit'), 'admin/build/forms/edit/' . $form_id);
$export = l(t('export FAPI code'), 'admin/build/forms/exportfapi/' . $form_id);
$exportable = l(t('export form'), 'admin/build/forms/export/' . $form_id);
// Determine modified status
if (($form['file'] || $form['database']) && $form['fbcache']) {
$status = t('database');
$delete = t('revert');
}
elseif ($form['file'] && $form['database']) {
$status = t('modified');
$delete = t('revert');
}
elseif ($form['file']) {
$delete = '';
}
elseif ($form['fbcache']) {
$status = t('unsaved');
}
// Link delete/revert button
$delete = (!empty($delete)) ? l($delete, "admin/build/forms/delete/$form_id") : '';
// Link $form_id
$form_path = db_result(db_query("SELECT path FROM {form_manager_settings} WHERE form_id='%s'", $form_id));
$form_id = (!empty($form_path)) ? l($form_id, $form_path) : l($form_id, "form/$form_id");
// Create the actual table rows.
$rows[] = array(
$form_id,
$status,
$edit . ' ' . $export . ' ' . $exportable . ' ' . $delete,
);
}
$bottom_links = l(t('Create a new form'), 'admin/build/forms/add') . ' ' . l(t('Import a form'), 'admin/build/forms/import');
$rows[] = array(
array('data' => $bottom_links, 'colspan' => 3),
);
// Spit out the themed table for output.
$output = theme('table', $headers, $rows);
return $output;
}
/**
* Helper function to list the forms of all available forms. When the same form exists in multiple
* locations (file, db, etc), the following precedence is used to return the form once:
* - file
* - Form Manager table (database)
* - Form Builder cache (temporary storage)
*
* @return
* An associative array containing all the forms.
* - Key: form_id
* - name: form_id
* - source: the source (database or file)
*/
function _form_manager_list_forms() {
// Get list of forms in files
$file_forms = _form_manager_list_forms_by_type('file');
// Get list of forms in form manager table
$db_forms = _form_manager_list_forms_by_type('database');
// Get list of forms in form builder cache
$fb_forms = _form_manager_list_forms_by_type('fbcache');
// Shuffle the sources together. Put db forms after file forms, so that they'll take precedence.
$forms = array_merge($file_forms, $db_forms, $fb_forms);
foreach ($forms as $form_id => $form) {
$forms[$form_id]['file'] = $file_forms[$form_id]['file'];
$forms[$form_id]['database'] = $db_forms[$form_id]['database'];
$forms[$form_id]['fbcache'] = $fb_forms[$form_id]['fbcache'];
}
return $forms;
}
/**
* Helper function to list the forms of a given source of a given type (file, database, etc).
*
* @param $type
* The source type of the form.
* - file: The forms stored in code in the forms directory with the filename of form_id.inc
* - database: The forms stored in the database. These may be unique or may override forms with the same form_id stored in a file. Forms stored in the database will take precedence.
* - fbcache: The forms stored in Form Builder's cache. Generally, these are forms that haven't been saved yet. These will take prcedence over all other forms.
*
* @return
* An associative array containing all the forms of the given source type.
* - Key: form_id
* - name: form_id
* - source: the source (form builder cache, database, or file)
*/
function _form_manager_list_forms_by_type($type = 'file') {
$forms = array();
switch($type) {
case 'file':
$forms_path = drupal_get_path('module', 'form_manager') . '/forms';
$mask = '.*\.inc$';
$files = file_scan_directory($forms_path, $mask);
foreach ($files as $file) {
$forms[$file->name] = array(
'name' => $file->name,
'source' => 'file',
$type => TRUE,
);
}
break;
case 'database':
$results = db_query("SELECT form_id FROM {form_manager_forms}");
while ($data = db_fetch_array($results)) {
$forms[$data['form_id']] = array(
'name' => $data['form_id'],
'source' => 'database',
$type => TRUE,
);
}
break;
case 'fbcache':
$results = db_query("SELECT form_id FROM {form_builder_cache} WHERE sid='%s'", session_id());
while ($data = db_fetch_array($results)) {
$forms[$data['form_id']] = array(
'name' => $data['form_id'],
'source' => 'file builder cache',
$type => TRUE,
);
}
break;
}
return $forms;
}
/**
* form function for exporting an entire FAPI array.
*/
function form_manager_export_form($form, $form_id) {
module_load_include('inc', 'form_builder', 'includes/form_builder.api');
module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
module_load_include('inc', 'form_manager', 'includes/form_manager.pages');
$form = array();
$form_state = array();
$current = array();
$current = form_builder_cache_load('form_manager', $form_id);
if (empty($current)) {
form_manager_get_form($current, $form_state, $form_id);
}
$form['form_manager'] = array(
'#type' => 'textarea',
'#title' => t('Export code'),
'#default_value' => form_manager_export($current),
'#attributes' => array('readonly' => 'readonly', 'style' => 'font-family: monospace;'),
'#rows' => 20,
);
return $form;
}
/**
* Menu callback for exporting an entire FAPI array.
*
* @param $form_id
* The form_id of the form to retreive.
*
* @return
* HTML output; the content of the page.
*/
function form_manager_export_form_page($form_id) {
$links = array();
$links[] = array(
'title' => t('list forms'),
'href' => 'admin/build/forms',
'attributes' => '',
'query' => '',
'fragment' => '',
);
$links[] = array(
'title' => t('edit'),
'href' => 'admin/build/forms/edit/' . $form_id,
'attributes' => '',
'query' => '',
'fragment' => '',
);
$output = '';
$output .= theme('links', $links, array('class' => 'tabs secondary'));
$output .= drupal_get_form('form_manager_export_form', $form_id);
return $output;
}
function form_manager_export($form) {
$output = '';
$output .= form_manager_export_recurse($form);
//$output .= 'return $form;';
return $output;
}
/**
* Recursive function for pretty-printing of FAPI arrays.
*/
function form_manager_export_recurse($form, $parents = array()) {
$output = '';
form_manager_reset_element_keys($form);
// Sort this level of the array according to weight.
uasort($form, 'element_sort');
// Print out this parent element and it's properties.
$properties = element_properties($form);
$omit = array('#form_builder', '#key', '#form_manager_form_id', '#element_name');
if (count($properties)) {
$output .= form_manager_export_variable_name($parents, $form) . " = array(\n";
foreach (element_properties($form) as $property) {
if (!in_array($property, $omit)) {
if (is_array($form[$property])) {
$output .= " '". $property . "' => array(\n";
foreach ($form[$property] as $key => $value) {
$output .= " '" . $key . "' => '". str_replace("'", "\'", $value) ."',\n";
}
$output .= " ),\n";
}
else {
$output .= " '". $property . "' => '" . str_replace("'", "\'", $form[$property]) ."',\n";
}
}
}
$output .= ");\n";
}
else {
//$output .= form_manager_export_variable_name($parents) . " = array();\n";
}
foreach (element_children($form) as $key) {
$parents[] = $key;
$output .= form_manager_export_recurse($form[$key], $parents);
array_pop($parents);
}
return $output;
}
function form_manager_export_variable_name($parents, $form = array()) {
$output = '$form';
foreach ($parents as $parent) {
$output .= "['". $parent ."']";
}
return $output;
}
/**
* Look for element_name and change the Form Builder default key name to this value.
*
* This really just makes a copy of the sub-array with the new key name, and unsets
* the original sub-array. It also unsets the element_name element just to make sure
* this doesn't act multiple times on the same element.
*/
function form_manager_reset_element_keys(&$form) {
foreach ($form as $key => $element) {
if (!empty($element['#element_name']) && is_array($element) && $element['#element_name'] != $key) {
$element_name = $element['#element_name'];
unset($element['#element_name']);
$form[$element_name] = $element;
unset($form[$key]);
}
}
}
/**
* Main form building interface. Can be used as a menu callback.
*
* @param $form_type
* The type of form being edited. Usually the name of the providing module.
* @param $form_id
* The unique identifier for the form being edited with the type.
*/
function form_manager_edit($form_type, $form_id) {
module_load_include('inc', 'form_builder', 'includes/form_builder.api');
module_load_include('inc', 'form_builder', 'includes/form_builder.cache');
module_load_include('inc', 'form_builder', 'includes/form_builder.admin');
// Set the current form type (used for display of the sidebar block).
form_builder_active_form($form_type, $form_id); // Is this a noop?
$form = _form_manager_load_form($form_type, $form_id);
$output = '';
$output .= drupal_get_form('form_builder_preview', $form, $form_type, $form_id);
$output .= drupal_get_form('form_builder_positions', $form, $form_type, $form_id);
$output .= drupal_get_form('form_manager_edit_actions');
return $output;
}
function _form_manager_load_form($form_type, $form_id) {
// Load the current state of the form, or create a new cache if needed.
$form = form_builder_cache_load($form_type, $form_id);
if (!$form) {
$form = form_builder_load_form($form_type, $form_id);
form_builder_cache_save($form_type, $form_id, $form);
}
return $form;
}
/**
* Form function to generate some options below the Form Builder set of forms to:
* - Save -- Copies the Form Builder cache into the Form Manager table (after making some slight alterations)
* - Export -- Generates a FAPI-appropriate array to copy
* - Cancel -- Cancel the form changes and go back to the main admin page
*/
function form_manager_edit_actions() {
$form = array();
$form['formid'] = array(
'#type' => 'hidden',
'#value' => check_plain(arg(4)),
);
// Buttons
$form['save'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
$form['export'] = array(
'#type' => 'submit',
'#value' => t('Export'),
);
$form['cancel'] = array(
'#type' => 'submit',
'#value' => t('Cancel'),
);
return $form;
}
/**
* Implementation of hook_submit to handle the form_manager_edit_actions form.
*/
function form_manager_edit_actions_submit(&$form, &$form_values) {
$values = $form_values['values'];
$op = $form_values['values']['op'];
switch($op) {
case 'Cancel':
// TODO: Use a confirm form to confirm and delete the form_builder_cache cached form
drupal_goto('admin/build/forms');
break;
case 'Save':
// TODO: Use a confirm form to confirm and delete the form_builder_cache cached form
_form_manager_edit_actions_submit_save($values);
break;
case 'Export':
// TODO: Use a confirm form to confirm and delete the form_builder_cache cached form
drupal_goto('admin/build/forms/export/' . $values['formid']);
break;
}
}
/**
* Helper function to save the form sent to form_manager_edit_actions_submit()
*/
function _form_manager_edit_actions_submit_save($values) {
$session = session_id();
// Copy the form_builder_cache'ed form to the form_manager_forms table (updating if necesary)
$fid = db_result(db_query("SELECT fid FROM {form_manager_forms} WHERE form_id='%s'", $values['formid']));
$form_cache = db_fetch_object(db_query("SELECT * FROM {form_builder_cache} WHERE sid='%s' AND form_id='%s'", $session, $values['formid']));
// Rename the element keys if they have been explicitely defined in the Form Builder edit page.
$form = unserialize($form_cache->data);
form_manager_reset_element_keys($form);
foreach (element_children($form) as $key) {
if (is_array($form[$key])) {
form_manager_reset_element_keys($form[$key]);
}
}
$form_cache->data = serialize($form);
// We don't care about session ID since the form will be saved permanently and not cached by session. Chuck it.
unset($form_cache->sid);
// Update the timestamp on the form.
$form_cache->updated = time();
// We need to know if this is a new form or if we're updating an existing form so that drupal_write_record
// can do the appropriate thing to save it.
$update = array();
if ($fid) {
$form_cache->fid = $fid;
$update[] = 'fid';
}
drupal_write_record('form_manager_forms', $form_cache, $update);
// Remove the form_builder_cache form (all for this session ID only)
db_query("DELETE FROM {form_builder_cache} WHERE sid='%s' AND form_id='%s'", $session, $values['formid']);
// redirect to admin page
drupal_goto('admin/build/forms');
}
/**
* confirm_delete function
* Confirm that the admin wants to delete the given form
*/
function form_manager_confirm_delete(&$form_state) {
$form_id = check_plain(arg(4));
$form_data = array(
'form_id' => $form_id,
'database' => db_result(db_query("SELECT fid FROM {form_manager_forms} WHERE form_id='%s'", $form_id)),
'fbcache' => db_result(db_query("SELECT form_id FROM {form_builder_cache} WHERE sid='%s' AND form_id='%s'", session_id(), $form_id)),
);
if (!empty($form_data['database']) || !empty($form_data['fbcache'])) {
$form_state['storage']['form_data'] = $form_data;
$form = array();
return confirm_form(
$form,
t('Are you sure you want to delete the form %form_id?', array('%form_id' => $form_id)),
'admin/build/forms',
t('You are about to delete the delete the form %form_id. This action cannot be undone.', array('%form_id' => $form_id)), t('Delete')
);
}
else {
drupal_set_message(t('That form does not exist in the database.'), $type = 'error', FALSE);
drupal_goto('admin/build/forms');
}
}
/**
* Form submit handler for the confirm delete form.
* Handles deletion of the specified form from the database.
*/
function form_manager_confirm_delete_submit($form, &$form_state) {
$form_data = $form_state['storage']['form_data'];
if (!empty($form_data['database'])) {
db_query("DELETE FROM {form_manager_forms} WHERE form_id='%s'", $form_data['form_id']);
}
if (!empty($form_data['fbcache'])) {
db_query("DELETE FROM {form_builder_cache} WHERE sid='%s' AND form_id='%s'", session_id(), $form_data['form_id']);
}
drupal_set_message(t('The form %formid has been deleted from the database.', array('%formid' => $form_data['form_id'])), $type = 'status', FALSE);
drupal_goto('admin/build/forms');
}
/**
* Form function to allow admin users to create a new form from scratch.
*/
function form_manager_add() {
$form = array();
// use 'formid' instead of 'form_id' in order to not confuse it with *this* form's form_id
$form['formid'] = array(
'#type' => 'textfield',
'#title' => t('Form ID'),
'#description' => t('This is the internal form_id of the form that will be used to uniquely identify it. Only letters, numbers, and underscores are allowed.'),
'#required' => TRUE,
);
$form['path'] = array(
'#type' => 'textfield',
'#title' => t('Path'),
'#description' => t('The path to the page that will display the form. ex. form/form_id'),
'#required' => TRUE,
);
$form['published'] = array(
'#type' => 'checkbox',
'#title' => t('Published?'),
'#description' => t('Whether or not the form is published. If it is not published, then only users with the administer form_manager forms will be able to view it. NOTE: This is not currently used. Future versions will allow you to enable/disable forms, but this functionality does not yet exist.'),
'#default_value' => TRUE,
);
$form['multistep'] = array(
'#type' => 'checkbox',
'#title' => t('Multi-Step?'),
'#description' => t('Whether or not the form is multi-step. Top-level fieldsets will be used to determine "pages" of form elements. NOTE: this is not currently implemented; all forms with fieldsets are currently assumed to be multi-step forms. This will change in future versions, and this checkbox is here to provide future compatability.'),
'#default_value' => TRUE,
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Create form'),
);
return $form;
}
/**
* @todo Ensure that the form_id submitted doesn't exist already.
* - as a file-based form
* - in the database or in Form Builder cache
* - as a hook or form from another module
*/
function form_manager_add_validate($form, &$form_state) {
// TODO: this function
}
/**
* Submit handler for add form function
*/
function form_manager_add_submit($form, &$form_state) {
// Save settings in the form_manager_settings table
$form_data = array(
'form_id' => $form_state['values']['formid'],
'path' => $form_state['values']['path'],
'status' => $form_state['values']['published'],
'multistep' => $form_state['values']['multistep'],
'update' => time(),
);
// TODO: Save the data in the form_manager_settings table, table needs to be added to hook_schema
//$form_data = (object) $form_data;
drupal_write_record('form_manager_settings', $form_data);
// Make sure the new form's path will be available
// TODO: I don't like rebuilding the menu_router table for the simple addition of a new callback function path.
// Find a better way to do this, like inserting it as a single row in {menu_router}.
menu_router_build();
// Send the user to the Form Builder edit page
drupal_goto('admin/build/forms/edit/' . $form_data['form_id']);
}
function form_manager_admin_exportable($formid = FALSE) {
$output = '';
ctools_include('export');
$result = ctools_export_load_object('form_manager_forms', 'conditions', array('form_id' => $formid));
drupal_set_title(check_plain($result->description));
$code = ctools_export_object('form_manager_forms', array_shift($result), '');
$lines = substr_count($code, "\n");
return drupal_get_form('ctools_export_form', $code, 'Form Manager form');
}
function form_manager_admin_import() {
$form['formid'] = array(
'#type' => 'textfield',
'#title' => t('Form name'),
'#description' => t('Enter the name of the new form. This is optional and is not necessary if you do not wish to rename the object.'),
);
$form['object'] = array(
'#type' => 'textarea',
'#title' => t('Paste form code here'),
'#rows' => 15,
);
$form['submit'] = array(
'#value' => t('Import'),
'#type' => 'submit',
);
return $form;
}
/**
* Make sure that an import actually provides a handler.
*/
function form_manager_admin_import_validate(&$form, &$form_state) {
// First, run the PHP and turn the input code into an object.
ob_start();
eval($form_state['values']['object']);
ob_end_clean();
// The object should appear as $formmanager. This was the "identifier" set in the export section of the schema.
if (empty($formmanager)) {
$errors = ob_contents();
if (empty($errors)) {
$errors = t('No formmanager object found.');
}
form_error($form['object'], t('Unable to get a formmanager from the import. Errors reported: @errors', array('@errors' => $errors)));
}
$formmanager->data = str_replace("\r\n", ' ', $formmanager->data);
// make sure we're not importing an existing form
if (!empty($form_state['values']['formid'])) {
$formmanager->form_id = $form_state['values']['formid'];
}
if (form_manager_formid_exists($formmanager->form_id)) {
$errors = t('That form_id @formid already exists.', array('@formid' => $formmanager->form_id));
form_error($form['object'], t('Unable to get a formmanager object from the import. Errors reported: @errors', array('@errors' => $errors)));
}
$form_state['obj'] = $formmanager;
}
/**
* Save the imported object.
*/
function form_manager_admin_import_submit(&$form, &$form_state) {
$formmanager = $form_state['obj'];
if (!empty($form_state['values']['name'])) {
$formmanager->form_id = $form_state['values']['name'];
}
form_manager_admin_import_save($formmanager);
$form_state['redirect'] = 'admin/build/forms/edit/' . $formmanager->form_id;
}
function form_manager_admin_import_save($formmanager) {
$update = array();
if (!empty($formmanager->name)) {
if (form_manager_formid_exists($formmanager->form_id)) {
$update[] = 'fid';
}
}
drupal_write_record('form_manager_forms', $formmanager, $update);
}
function form_manager_formid_exists($formid) {
$fid = db_result(db_query("SELECT fid FROM {form_manager_forms} WHERE form_id='%s'", $formid));
if (!empty($fid)) {
return 'fid';
}
return FALSE;
}