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('&lt;!tag&gt; 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

vaish’s picture

You 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.

johnbarclay’s picture

Status: Active » Needs review
StatusFileSize
new1.29 KB
new1.33 KB
new9.18 KB

Thanks. 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.

<actions>
<ldapauth_server>
    <name>UIUC AD LDAP</name>
    <server>ad.uiuc.edu</server>
    ....


 <ldapgroups_server>
    <name>UIUC AD LDAP</name>

    <ldapgroups_in_dn>1</ldapgroups_in_dn>
    <ldapgroups_dn_attribute>ou</ldapgroups_dn_attribute>
   ...
</actions>
vaish’s picture

I 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.

johnbarclay’s picture

Title: Creating a Pattern for a basic module configuration form. Need pointing in right direction. » LDAP Integration Component: ...was Creating a Pattern for a basic module configuration form. Need pointing in right direction.
Component: Miscellaneous » Code
Category: support » feature
StatusFileSize
new10.7 KB
new19.44 KB

O.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.

vaish’s picture

Status: Needs review » Needs work

I 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

    ob_start();
    require_once("$path". $pattern_file);
    $content = ob_get_contents();
    ob_end_clean();

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()?

  require_once(drupal_get_path('module','ldapgroups') .'/ldapgroups.admin.inc');
  module_load_include('inc', 'ldapgroups', 'ldapgroups.admin');

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

johnbarclay’s picture

Thank 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.