Forgive me -- this is my first attempt at writing a module. This is the admin menu for a module that will perform external auth with an in-house system we have at my company. I'm going to implement that with hook_boot(). But that's later. First, a few easier questions:

1. I had to "steal" some code from system_settings_form() because, as far as I could tell, in a system form, you can't override the #submit handler. I was finding that the my_auth_admin_submit function was never being called. I wanted to save my settings into a custom database table rather than the variables table, and this was the only way I could figure out how to do it. Is this the right approach?

2. I found that in my_auth_admin_submit, if I attempted to foreach through $form_state['values'], I could get the "new" item submitted, but for all the other form items, $form_state['values'] was being overwritten with the values already in the database and not the ones just posted! The only way I could figure out how to get at the newly-posted values was to use $form['#post'] instead. But this doesn't seem right and doesn't look like most of the examples I've seen. What am I doing wrong?

Thanks!

Code below:


function my_auth_help($path, $arg) {
	$output = '';
	switch ($path) {
		case "admin/help#my_auth" :
			$output = '<p>' . t ( "Provides external auth functionality" ) . '</p>';
			break;
	}
	return $output;
}

function my_auth_perm() {
	return array ('configure my_auth' );
}

function my_auth_admin() {
	
	// get existing configuration
	$sql = "select apps.id as app_pk, apps.app_name, apps.enabled, apps.login_type, apps.default_role, pages.id as page_pk, pages.app_id, pages.page_pattern from {my_auth_applications} apps, {my_auth_applications_pages} pages where apps.id = pages.app_id order by apps.app_name";
	$result = db_query ( $sql );
	
	$form = array ();
	
	while ( $data = db_fetch_object ( $result ) ) {
		$form [$data->app_pk] = array ('#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => TRUE, '#title' => 'External Auth Application ' . $data->app_name, '#description' => 'Configuration for External Auth Application ' . $data->app_name );
		$form [$data->app_pk] ['app_enabled_' . $data->app_pk] = array ('#title' => 'Enabled', '#description' => 'Make this restriction active', '#type' => 'checkbox', '#required' => TRUE, '#value' => $data->enabled == 'Y' );
		$form [$data->app_pk] ['app_name_' . $data->app_pk] = array ('#title' => 'External Auth Application ID', '#description' => 'The ID of the External Auth Application registered with IT', '#type' => 'textfield', '#required' => TRUE, '#value' => $data->app_name );
		$form [$data->app_pk] ['app_type_' . $data->app_pk] = array ('#title' => 'Restriction Type', '#description' => 'ANON = Protect page only (anonymous Drupal user); AUTO = Auto-provision new Drupal users into specified default role; PROV = Only allow pre-provisioned Drupal users', '#type' => 'select', '#required' => TRUE, '#value' => $data->login_type, '#options' => array ('ANON' => 'ANON', 'AUTO' => 'AUTO', 'PROV' => 'PROV' ) );
		$form [$data->app_pk] ['app_role_' . $data->app_pk] = array ('#title' => 'Default Role', '#description' => 'The role that should be assigned to auto-provisioned users (only applies to type PROV)', '#type' => 'textfield', '#required' => FALSE, '#value' => $data->default_role );
		$form [$data->app_pk] ['app_pattern_' . $data->app_pk] = array ('#title' => 'Page Pattern Match', '#description' => 'The URL pattern to apply to this External Auth Application (if multiple applications match a page, the first one to match is the one that will be used)', '#type' => 'textarea', '#required' => TRUE, '#value' => $data->page_pattern );
	}
	
	$form ['new'] = array ('#type' => 'fieldset', '#collapsible' => TRUE, '#collapsed' => TRUE, '#title' => 'New External Auth Application', '#description' => 'Configuration a new External Auth Application' );
	$form ['new'] ['app_enabled_new'] = array ('#title' => 'Enabled', '#description' => 'Make this restriction active', '#type' => 'checkbox', '#required' => TRUE, '#default_value' => TRUE );
	$form ['new'] ['app_name_new'] = array ('#title' => 'External Auth Application ID', '#description' => 'The ID of the External Auth Application registered with IT', '#type' => 'textfield', '#required' => TRUE );
	$form ['new'] ['app_type_new'] = array ('#title' => 'Restriction Type', '#description' => 'ANON = Protect page only (anonymous Drupal user); AUTO = Auto-provision new Drupal users into specified default role; PROV = Only allow pre-provisioned Drupal users', '#type' => 'select', '#required' => TRUE, '#options' => array ('ANON' => 'ANON', 'AUTO' => 'AUTO', 'PROV' => 'PROV' ) );
	$form ['new'] ['app_role_new'] = array ('#title' => 'Default Role', '#description' => 'The role that should be assigned to auto-provisioned users (only applies to type PROV)', '#type' => 'textfield', '#required' => FALSE );
	$form ['new'] ['app_pattern_new'] = array ('#title' => 'Page Pattern Match', '#description' => 'The URL pattern to apply to this External Auth Application (if multiple applications match a page, the first one to match is the one that will be used)', '#type' => 'textarea', '#required' => TRUE );
	
	// borrowed from modules/system/system.module system_settings_form() because normally you can't override the system forms submit handler
	

	$form ['buttons'] ['submit'] = array ('#type' => 'submit', '#value' => t ( 'Save configuration' ) );
	if (! empty ( $_POST ) && form_get_errors ()) {
		drupal_set_message ( t ( 'The settings have not been saved because of the errors.' ), 'error' );
	}
	$form ['#submit'] [] = 'my_auth_admin_submit';
	$form ['#theme'] = 'system_settings_form';
	
	return $form;

}

function my_auth_menu() {
	$items = array ();
	$items ['admin/settings/my_auth'] = array ('title' => 'my Auth module settings', 'description' => 'my Auth module settings', 'page callback' => 'drupal_get_form', 'page arguments' => array ('my_auth_admin' ), 'access arguments' => array ('configure my_auth' ), 'type' => MENU_NORMAL_ITEM );
	return $items;
}

function my_auth_admin_submit($form, &$form_state) {
	
	// borrowed from modules/system/system.module system_settings_form_submit() because normally you can't override the system forms submit handler
	

	foreach ( $form ['#post'] as $key => $value ) {
		if (strstr ( $key, "app_name_" ) != FALSE) {
			preg_match ( "/^app_name_(.*)$/", $key, $matches );
			$id = $matches [1];
			$app_name = $form ['#post'] ['app_name_' . $id];
			$enabled = $form_state ['values'] ['app_enabled_' . $id] == 1 ? 'Y' : 'N';
			$login_type = $form ['#post'] ['app_type_' . $id];
			$default_role = $form ['#post'] ['app_role_' . $id];
			$pattern = $form ['#post'] ['app_pattern_' . $id];
			if ($id == "new") {
				// new record
				$sql = "insert into {my_auth_applications} (app_name, enabled, login_type, default_role) values ('%s', '%s', '%s', '%s')";
				$result = db_query ( $sql, $app_name, $enabled, $login_type, $default_role );
				$sql = "select id from {my_auth_applications} where app_name = '%s'";
				$result = db_query ( $sql, $app_name );
				$data = db_fetch_object ( $result );
				$id = $data->id;
				$sql = "insert into {my_auth_applications_pages} (app_id, page_pattern) values (%d, '%s')";
				$result = db_query ( $sql, $id, $pattern );
			} else {
				// existing record
				$sql = "update {my_auth_applications} set app_name = '%s', enabled = '%s', login_type = '%s', default_role = '%s' where id = %d";
				$result = db_query ( $sql, $app_name, $enabled, $login_type, $default_role, $id );
				$sql = "update {my_auth_applications_pages} set page_pattern = '%s' where app_id = %d";
				$result = db_query ( $sql, $pattern, $id );
			}
		}
	}
	
	drupal_set_message ( t ( 'The configuration options have been saved.' ) );
	
	cache_clear_all ();
	drupal_rebuild_theme_registry ();

}

Comments

mooffie’s picture

I found that in my_auth_admin_submit [...] $form_state['values'] was being overwritten with the values already in the database and not the ones just posted!

Do

$form['spouse_name'] = array(
  '#type' => 'textfield',
  '#default_value' => $person->spouse_name,
);

instead of

$form['spouse_name'] = array(
  '#type' => 'textfield',
  '#value' => $person->spouse_name,
);

('#value' is used to tell the browser what to show in the field. In other words, it's for FAPI to figure out. Usually not for you. On the other hand, #value is also used for fields that don't get input from the user; e.g., buttons, hidden fields, value fields.)

as far as I could tell, in a system form, you can't override the #submit handler.

You can unset its submit handler:

$form = system_settings_form(...);
unset($form['#submit']);

But removing this submit handler, which is probably the only useful thing about system_settings_form, also removes much of the reason to use system_settings_form in the first place.

mlevin’s picture

Thanks for the help with the #value vs #default_value confusion!

As for the system_settings_form, since I want to save my values into a custom table, I may as well skip system_settings_form and just roll my own?

- m

mooffie’s picture

I may as well skip system_settings_form and just roll my own?

Yes. You don't need to use system_settings_form().