[phpldapadmin] implementing per template post function hook - please help!

Alexander 'Leo' Bergolth <[email protected]> Mon, 28 Feb 2011 14:59:12 +0100
Newsgroups gmane.comp.ldap.davedap
Message-ID <[email protected]>
Hi!

I am currently implementing a <post> function that is called per
template (as opposed to the existing per attribute post functions).

The main purpose of this hook for user defined functions is to allow
- consistency-checks that involve more than one attribute
- setting ldap attributes based on the value of other attribute
- doing actions that should only be done once and immediately before
entry creation. (E.g. getting a new userid with get_next_number should
be done here if you want to avoid wasting userids.)

The function should be called just before the entry is created or
updated. Depending on the functions return code, it should be possible
to issue a warning message and redirect to the form. (If the entries
attributes didn't pass the consistency check.)

Writing an example custom function and implementing the post-hook was
not a big problem. (The patch and an example function are attached.)
But now I am struggling to find a good place to call the hook.

The idea was to add
  $success = $request['template']->postFunc();
to htdocs/create.php and htdocs/update.php between
$request['page']->accept()
and
$app['server']->add() (or modify()).

But if the return code of the function is false, I'd like to return to
the create- or modify-form.

Do you have any hints how to do that?

Thanks in advance,
--leo

P.S.: To include the attached post function, add something like that to
the template:

-------------------- 8< --------------------
<template>
<title>RK User</title>
<visible>1</visible>

<post>=php.Function(tmpl_rk_user_postfunc;$template$,testarg)</post>
<post>=php.Function(tmpl_rk_user_postfunc;$template$,testarg2)</post>
-------------------- 8< --------------------

-- 
e-mail   ::: Leo.Bergolth (at) wu.ac.at
fax      ::: +43-1-31336-906050
location ::: IT-Services | Vienna University of Economics | Austria

------------------------------------------------------------------------------
Free Software Download: Index, Search & Analyze Logs and other IT data in 
Real-Time with Splunk. Collect, index and harness all the fast moving IT data 
generated by your applications, servers and devices whether physical, virtual
or in the cloud. Deliver compliance at lower cost and gain new business 
insights. http://p.sf.net/sfu/splunk-dev2dev

______________________________________
phpLDAPadmin development mailing list.
To unsbuscribe: https://lists.sourceforge.net/lists/listinfo/phpldapadmin-devel
http://phpldapadmin.sourceforge.net/
phpldapadmin-template-post.patch (text/x-patch, 3.8 KB)
--- ../../../scratch/sw/phpldapadmin/orig/usr/share/phpldapadmin/lib/Template.php	2010-09-23 16:10:07.000000000 +0200
+++ lib/Template.php	2011-02-28 14:42:31.000000000 +0100
@@ -55,6 +55,8 @@
 	private $icon;
 	# Template RDN attributes
 	private $rdn;
+	# Post template function
+	private $post = array();
 
 	public function __construct($server_id,$name=null,$filename=null,$type=null,$id=null) {
 		parent::__construct($server_id,$name,$filename,$type,$id);
@@ -147,6 +149,24 @@
 
 					break;
 
+			        case('post'):
+					if (! is_array($xml_value))
+						$xml_value = array($xml_value);
+					$this->post = array();
+					foreach ($xml_value as $val) {
+						if (preg_match('/^=php\.(\w+)\((.*)\)$/',$val,$matches)) {
+							$this->post[] = array('function' => $matches[1],
+									      'args' => $matches[2]);
+						} else
+							if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
+								system_message(array(
+								        'title'=>sprintf('%s',_('Unknown XML setting')),
+								        'body'=>sprintf('%s <small>[%s]</small>',_('Unknown XML type setting will be ignored.'),$val),
+								        'type'=>'warn'));
+					}
+					# error_log("LEO: post: ".print_r($this->post, 1));
+					break;
+
 				default:
 					if (DEBUG_ENABLED)
 						debug_log('Case [%s]',4,0,__FILE__,__LINE__,__METHOD__,$xml_key);
@@ -1515,5 +1535,85 @@
 	public function isNoLeaf() {
 		return $this->noleaf;
 	}
+
+	/**
+	 * Function enables normal PHP functions to be called to evaluate a value.
+	 * eg: =php.Function(date;dmY)
+	 *
+	 * All arguments will be passed to the function, and its value returned.
+	 * If this used used in a POST context, the attribute values can be used as arguments.
+	 *
+	 * Mandatory Arguments:
+	 * * arg 0
+	 *   - php Function to call
+	 *
+	 * Additional arguments will be passed to the function.
+	 */
+	public function phpFunction($type, $attribute, $args) {
+		$function = array_shift($args);
+
+		if (count($args) && count($args) > 1) {
+			system_message(array(
+				'title'=>_('Too many arguments'),
+				'body'=>sprintf('%s (<b>%s</b>)',_('Function() only takes two arguments and more than two were specified'),count($args)),
+				'type'=>'warn'));
+
+			return;
+		}
+
+		$function_args = explode(',',$args[0]);
+
+		foreach($function_args as &$arg) {
+			switch ($arg) {
+			        case '$attribute$':
+					$arg = $attribute;
+					break;
+			        case '$template$':
+					$arg = $this;
+					break;
+			}
+		}
+		# error_log("LEO: Function: $function; ".print_r($function_args, 1)."\n");
+		if (function_exists($function))
+			$vals = call_user_func_array($function,$function_args);
+		else
+			system_message(array(
+				'title'=>_('Function doesnt exist'),
+				'body'=>sprintf('%s (<b>%s</b>)',_('An attempt was made to call a function that doesnt exist'),$function),
+				'type'=>'warn'));
+		return $vals;
+	}
+
+	public function postFunc() {
+		if (DEBUG_ENABLED && (($fargs=func_get_args())||$fargs='NOARGS'))
+			debug_log('Entered (%%)',5,0,__FILE__,__LINE__,__METHOD__,$fargs);
+		
+		$functions = $this->post;
+		# error_log("LEO: postFunc ".print_r($functions, 1)."\n");
+
+		if (! count($functions))
+			return true;
+
+		foreach ($functions as $func) {
+			$funcname = $func['function'];
+			$funcargs = $func['args'];
+			$args = explode(';',$funcargs);
+			switch ($funcname) {
+			        case 'Function':
+					if (! $this->phpFunction('posttemplate', null, $args))
+						return false;
+					break;
+				default:
+					if (! $_SESSION[APPCONFIG]->getValue('appearance','hide_template_warning'))
+						system_message(array(
+							'title'=>sprintf('%s [<i>%s</i>]',_('Unknown template [post] function'),$funcname),
+							'body'=>sprintf('%s <small>[=php.%s(%s)]</small>',_('The template function is not known and will be ignored.'),$funcname,$funcargs),
+							'type'=>'warn'));
+
+			}
+			
+		}
+		return true;
+	}
 }
 ?>
functions.custom.php (text/html, 1.9 KB)
<?php

# LEO: Must be linked to /usr/share/phpldapadmin/lib/
# ln -s /etc/phpldapadmin/functions.custom.php /usr/share/phpldapadmin/lib/

$my_maildomain= 'klbg.n.roteskreuz.at';

function tmpl_rk_user_postfunc($template, $type) {
  $args = func_get_args();
  array_shift($args);
  global $app;
  # error_log("LEO: ".__METHOD__.": ".print_r($args, 1).", app: ".print_r($app, 1)."\n");
  # $template->getContext() (create || edit)
  # $template->isType('creation') || 'modification'

  $cnvals = $template->getAttribute('cn')->getValues();

  $uid = $template->getAttribute('uid')->getValues();
  if (count($uid) == 1)
    $uid = $uid[0];
  else
    return;
  
  if ($template->isType('creation')) {
    $maillocal = $template->getAttribute('maillocaladdress');
    if (! $maillocal->getValueCount()) {
      $maillocal->addValue($uid);

      if (count($cnvals)) {
	# add givenname.sn mail aliases
	$m = preg_replace('/^[^a-zA-Z]*(.*)[^a-zA-Z]*/', '$1', $cnvals[0]);
	$m = preg_replace('/[^a-zA-Z0-9]+/', '.', $m);
	if ($m) {
	  $maillocal->addValue($m);
	}
      }
    }

    $mail = $template->getAttribute('mail');
    if ($maillocal->getValueCount()) {
      $newmail = array();
      global $my_maildomain;
      foreach ($maillocal->getValues() as $ml) {
	$newmail[] = $ml.'@'.$my_maildomain;
      }
      $mail->setValue($newmail);
    }
  } else {
    # modification template
    1;
  }

  foreach (array('displayname', 'gecos') as $a) {
    $template->getAttribute($a)->setValue($cnvals);
  }

  system_message(array(
		       'title'=>_('Testerror'),
		       'body'=>sprintf('Leo Test Error'),
		       'type'=>'warn'));

  $server = $app['server'];
  # TODO: $template->server is private not available
  #$server->checkUniqueAttrs($template->getDN(),$template->getLDAPadd());

  # TODO:
  # use return value

  if ($template->isType('creation')) {
    # TODO
    # get_next_number if everything succeeds
  }
}

?>