I'm trying to create a pattern for configuring LDAP Integration. Partly to share configurations and automate installs; but also to learn how to write them for other modules.
I have a simple form for the ldap_integration module (path = admin/settings/ldap/ldapauth; form_id = ldapauth_admin_settings) that I just want to write a pattern for. Is there a generic way to write a pattern for a form, or do I need to write some code that goes in the components section in an ldap_integration.inc file? I wrote an ldap_integration.inc file and got it to work, but seems overly complex for just submitting a form. Below is the file and the pattern I'm using is.
<?php
/**
<actions>
<ldapauth_settings>
<login_process>0</login_process>
<login_conflict>0</login_conflict>
<forget_passwords>0</forget_passwords>
<sync_passwords>0</sync_passwords>
<disable_pass_change>0</disable_pass_change>
<alter_email_field>0</alter_email_field>
</ldapauth_settings>
</actions>
**/
function ldap_integration_patterns_ldapauth_settings_mappings() {
$mappings = array(
'login_process' =>
array('field_name' => 'ldapauth_login_process', 'required' => 1),
'login_conflict' =>
array('field_name' => 'ldapauth_login_conflict','required' => 1),
'forget_passwords' =>
array('field_name' => 'ldapauth_forget_passwords','required' => 1),
'sync_passwords' =>
array('field_name' => 'ldapauth_sync_passwords','required' => 1),
'disable_pass_change' =>
array('field_name' => 'ldapauth_disable_pass_change','required' => 1),
'alter_email_field' =>
array('field_name' => 'ldapauth_alter_email_field', 'required' => 1),
);
return $mappings;
}
function ldap_integration_patterns_req($mappings, $data) {
dpm('ldap_integration_patterns_req'); dpm($mappings); dpm($data);
$missing = array();
foreach ($mappings as $tag => $params) {
if (!array_key_exists($params['field_name'], $data) && $params['required']) { // need to check existance of tag, even if value is 0, NULL, empty etc.
$missing[] = t('<!tag> tag is missing.', array('!tag' => $tag));
}
}
return join("<br/>", $missing);
}
function ldapauth_patterns($op, $id = null, &$data = null, $a = null) {
dpm("ldap_integration_patterns $op , $id"); dpm($data); dpm($a);
$ldapauth_settings_mappings = ldap_integration_patterns_ldapauth_settings_mappings();
switch($op) {
// Return the valid tags that this component can prepare and process
case 'tags':
return array('ldapauth_settings', 'ldapauth_server', 'ldapgroups_server');
break;
// Return a list of forms/actions this component can handle
case 'actions':
return array(
'ldapauth_admin_settings' => t('Edit overall settings for ldap_integration module'),
'ldapauth_admin_form' => t('Edit single ldap server for authentication.'),
'ldapgroups_admin_form' => t('Edit single ldap server for ldap to drupal role mapping.'),
);
break;
// Prepare the data
case 'prepare':
if ($id == 'ldapauth_settings') {
dpm("<h2>prepare</h2>"); dpm($data);
foreach($ldapauth_settings_mappings as $tag => $params) {
$field_name = $params['field_name'];
dpm("<hr/>$tag, $field_name");
if (array_key_exists($tag, $data) && empty($data[$field_name])) {
$data[$field_name] = $data[$tag];
unset($data[$tag]);
}
}
dpm($data);
}
else if ($id == 'ldapauth_server') {
}
else if ($id == 'ldapgroups_server') {
}
break;
// Validate the values for an action before running the pattern
case 'pre-validate':
if ($id == 'ldapauth_settings') {
if ($missing = ldap_integration_patterns_req($ldapauth_settings_mappings, $data)) {
return $missing;
}
}
else if ($id == 'ldapauth_server') {
}
else if ($id == 'ldapgroups_server') {
}
break;
// Validate action before processing
case 'validate':
break;
// Return the form id or determine if the action does not need processing
case 'form_id':
if ($id == 'ldapauth_settings') {
return 'ldapauth_admin_settings';
}
else if ($id == 'ldapauth_server') {
// delete, add, or update form names. should all be the same form id for ldap
}
else if ($id == 'ldapgroups_server') {
return 'display';
}
break;
// Add default values to the pattern where appropriate and return form data
case 'build':
// require any ldap integration modules to get defaults.
// module_load_include('inc', 'content', 'includes/content.admin');
$data['op'] = 'Save configuration';
$data['form_id'] = 'ldapauth_admin_settings';
if ($id == 'ldapauth_admin_settings') {
// module_load_include( 'inc', 'ldapauth', 'admin');
// could set defaults here, but there are none.
}
dpm("build data:"); dpm($data);
return $data;
break;
// Create extra parameters needed for a pattern execution
case 'params':
if ($id == 'ldapauth_admin_settings') {
}
break;
// Any last cleanup items
case 'cleanup':
break;
}
}
Comments
Comment #1
vaish commentedYou can use "form" action to write actions for forms that are not covered by existing components.
Please check out documentation and example at http://drupal.org/node/408960 and let me know if you have any further questions.
Comment #2
johnbarclay commentedThanks. I can see how that could be accomplished. Attached is an ldap_integration.inc file and some sample patterns. The excercise was useful to me even if the "form" approach might make more sense than writing a special .inc file. The form state extras bit really made this feasible.
The critical thing for the ldap module is to map an ldap "name" to ldap server and group configurations. So the form construct would need to have some embedded php that queried for the sid based on the server name and dynamically decided if it was an add or update. It gets a little tricky.
Feel free to add this to the "components" part if the code looks correct. I've tested the patterns themselves and they work. If you commit it, I'll gladly document it in whatever format you like.
Comment #3
vaish commentedI still didn't have a chance to look at your code but would definitely love to include it with the module. So if you want to create documentation or if you have an updated version, please go ahead and post it here. Thanks for working on this.
Comment #4
johnbarclay commentedO.K. Here it is. I wasn't sure how to document it so I added a help function in hook_patterns such that the documentation could be added in the component itself. The documentation generated from it is in the attached html document.
Comment #5
vaish commentedI checked out your patch and found few things that need fixing and/or improving:
1. hook_menu()
Both menu items you are defining have '#type' defined twice. Remove the extra one and make sure to have only one item defined as DEFAULT_LOCAL TASK within the loop and all others as LOCAL_TASK
2. ldapauth.inc
I believe this should be replaced with file_get_contents($path . $pattern_file)
3. ldapauth_patterns_req() and ldapgroups_patterns_req() are basically identical. Would it be possible to have single function shared by both inc files? There are probably other parts of code that are duplicated in both files and that should be shared.
4. ldapgroups.inc
Why not use module_load_include instead() of require_once()?
5. both inc files
Why are you setting $form_id outside of switch statement? This is normally done within 'form_id' case.
6. Coding standards
Arrays, indentation, if statements, etc don't follow Drupal coding standards in may places. Same applies to XML files.
7. Sample patterns are incomplete. If run on clean Drupal install, 'ldap_modules_and_perms' will fail because admin role has not been created before setting permissions for it. If my understanding of ldap module is correct you also configure it to map ldapgroups to role "campus accounts" which doesn't exist.
Thanks
Comment #6
johnbarclay commentedThank you for looking this over with a great degree of detail. I agree with all your comments and will correct them and adjust the examples.