Commit f287852c authored by Carsten  Rose's avatar Carsten Rose
Browse files

Typeahead (#3369): Parameternames has changed, configuration is possible on...

Typeahead (#3369): Parameternames has changed, configuration is possible on the Form and on the FormElement.
typeahead.php: if there is an exception, the message body is sent as regular 'content' for the dropdownbox. At the moment this is the only way to transmit any error messages.
Ldap.php: missing FE_TYPEAHEAD_LDAP_KEY_PRINTF, FE_TYPEAHEAD_LDAP_VALUE_PRINTF will be substituted by the other. If both missing, an exception is thrown.
parent a2ef3c90
......@@ -862,31 +862,46 @@ parameter
* Comments: lines starting with a '#' are treated as a comment and will not be parsed.
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| Name | Type | Description |
+========================+========+==========================================================================================================+
| maxVisiblePill | int | Show pills upto <maxVisiblePill> as button, all further in a dropdown menu. Eg.: maxVisiblePill=3 |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| class | string | HTML div with given class, surrounding the whole form. Eg.: class=container-fluid |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| classPill | string | HTML div with given class, surrounding the `pill` title line. |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| classBody | string | HTML div with given class, surrounding all *FormElement*. |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| submitButtonText | string | Show save button, with the <submitButtonText> at the bottom of the form |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| extraDeleteForm | string | Name of a form which specifies how to delete the primary record and optional slave records |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-pattern-error | string | Pattern violation: Text for error message used for all FormElements of current form |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-required-error | string | Required violation: Text for error message used for all FormElements of current form |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-match-error | string | Match violation: Text for error message used for all FormElements of current form |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-error | string | If none specific is defined: Text for error message used for all FormElements of current form |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
| buttonOnChangeClass | string | Color for save button after user modified some content or current form. E.g.: 'btn-info alert-info' +
+------------------------+--------+----------------------------------------------------------------------------------------------------------+
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| Name | Type | Description |
+==========================+========+==========================================================================================================+
| maxVisiblePill | int | Show pills upto <maxVisiblePill> as button, all further in a dropdown menu. Eg.: maxVisiblePill=3 |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| class | string | HTML div with given class, surrounding the whole form. Eg.: class=container-fluid |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| classPill | string | HTML div with given class, surrounding the `pill` title line. |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| classBody | string | HTML div with given class, surrounding all *FormElement*. |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| submitButtonText | string | Show save button, with the <submitButtonText> at the bottom of the form |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| extraDeleteForm | string | Name of a form which specifies how to delete the primary record and optional slave records |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-pattern-error | string | Pattern violation: Text for error message used for all FormElements of current form |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-required-error | string | Required violation: Text for error message used for all FormElements of current form |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-match-error | string | Match violation: Text for error message used for all FormElements of current form |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| data-error | string | If none specific is defined: Text for error message used for all FormElements of current form |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| buttonOnChangeClass | string | Color for save button after user modified some content or current form. E.g.: 'btn-info alert-info' +
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapServer | string | FQDN Ldap Server. E.g.: ldap.example.com |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapBaseDn | string | E.g.: ou=dept,dc=example,dc=com |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| ldapSearch | string | E.g.: (|(cn=*?*)(mail=*?*)(ou=*?*)(roomNumber=*?*)(telephoneNumber=*?*)) |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLimit | int | Maximum number of entries. The limit is applied to the server (LDAP or SQL) and the Client |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadMinLength | int | Minimum number of characters which have to typed to start the search. |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapValuePrintf | string | Value formatting of LDAP result, per entry. E.g.: '%s / %s / %s', mail, roomnumber, telephonenumber |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| typeAheadLdapKeyPrintf | string | Key formatting of LDAP result, per entry. E.g.: '%s', mail |
+--------------------------+--------+----------------------------------------------------------------------------------------------------------+
* Example:
......@@ -1398,9 +1413,9 @@ Type Ahead
''''''''''
Activating `typeahead` functionality offers an instant lookup of data and displaying them to the user, while the user is
typing. A dropdown box offers the results. As datasource the regular SQL connection or a LDAP query can be used.
typing a dropdown box offers the results. As datasource the regular SQL connection or a LDAP query can be used.
With every keystroke (starting from the *typeAheadMinLength* characters), the already typed value will be transmitted to
the server, the lookup will be performed and the result is displayed as the dropdown box.
the server, the lookup will be performed and the result, upto *typeAheadLimit* entries, are displayed as the dropdown box.
* *FormElement.parameter*:
......@@ -1410,6 +1425,11 @@ the server, the lookup will be performed and the result is displayed as the drop
Depending of the `typeahead` setup, the given FormElement will contain the displayed `value` or `key` (if a key/value dict is
configured).
Configuration via Form / FormElement
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
All of the `typeAhead*` (exception: `typeAheadLdap`) and `ldap*` parameter can be specified in either on the Form.parameter or on FormElement.parameter.
SQL
;;;
......@@ -1427,9 +1447,11 @@ LDAP
* *FormElement.parameter*:
* *typeAheadLdapServer* = FQDN of the searched server. E.g.: `directory.uzh.ch`
* *typeAheadLdapBaseDn* = Base DN. E.g.: `ou=Addressbook,dc=uzh,dc=ch`
* *typeAheadLdapSearch* = LDAP search expression. E.g.: `(|(cn=*?*)(mail=*?*)(ou=*?*)(roomNumber=*?*)(telephoneNumber=*?*))`
* *typeAheadLdap* This entry activates the *LDAP* typeahead functionality.
* *ldapServer* = FQDN of the searched server. E.g.: `directory.uzh.ch`
* *ldapBaseDn* = Base DN. E.g.: `ou=Addressbook,dc=uzh,dc=ch`
* *ldapSearch* = LDAP search expression. Every '?' will be replaced with the current typed content.
E.g.: `(|(cn=*?*)(mail=*?*)(ou=*?*)(roomNumber=*?*)(telephoneNumber=*?*))`
* *typeAheadLdapValuePrintf* = regular printf expression, LDAP attributenames will be used as variablenames. Will be shown
in the dropdownbox. E.g.: `'%s / %s / %s', mail, roomNumber, telephoneNumber`
* *typeAheadLdapKeyPrintf* = Same as `ldapValuePrintf` - on save, these content will be saved. E.g.: `'%s', mail`
......
......@@ -19,15 +19,14 @@ require_once(__DIR__ . '/../qfq/Constants.php');
* Return JSON encoded answer
*
*/
try {
$qfq = new \qfq\TypeAhead();
$answer = $qfq->process();
} catch (\Exception $e) {
$answer[API_MESSAGE] = "Generic Exception: " . $e->getMessage();
// $answer[API_MESSAGE] = "Generic Exception: " . $e->getMessage();
$answer[] = [API_TYPEAHEAD_KEY => 'errror', API_TYPEAHEAD_VALUE => "Error: " . $e->getMessage()];
}
header("Content-Type: application/json");
......
......@@ -382,6 +382,10 @@ abstract class AbstractBuildForm {
// Preparation for Log, Debug
$this->store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($fe), STORE_SYSTEM);
if (isset($fe[FE_FILL_STORE_LDAP]) || isset($fe[FE_TYPEAHEAD_LDAP])) {
$fe = $this->prepareLdapConfig($fe);
}
// for Upload FormElements, it's necessary to precalculate an optional given 'slaveId'.
if ($fe[FE_TYPE] === FE_TYPE_UPLOAD) {
Support::setIfNotSet($fe, FE_SLAVE_ID);
......@@ -461,6 +465,24 @@ abstract class AbstractBuildForm {
return $html;
}
/**
* Copy LDAP Server from $this->formSpec to $formElement if they are not specified on $formElement
* @param array $formElement
* @return array
*/
private function prepareLdapConfig(array $formElement) {
foreach ([F_LDAP_SERVER, F_LDAP_BASE_DN, F_LDAP_SEARCH, F_TYPEAHEAD_LIMIT,
F_TYPEAHEAD_MINLENGTH, F_TYPEAHEAD_LDAP_VALUE_PRINTF, F_TYPEAHEAD_LDAP_KEY_PRINTF] as $key) {
if (!isset($formElement[$key])) {
if (isset($this->formSpec[$key])) {
$formElement[$key] = $this->formSpec[$key];
}
}
}
return $formElement;
}
/**
* Check if there is an explicit 'autofocus' definition in at least one FE.
* Found: do nothing, it will be rendered at the correct position.
......@@ -824,17 +846,17 @@ abstract class AbstractBuildForm {
if (isset($formElement[FE_TYPEAHEAD_SQL])) {
$sql = $this->checkSqlAppendLimit($formElement[FE_TYPEAHEAD_SQL], $formElement[FE_TYPEAHEAD_LIMIT]);
$urlParam = FE_TYPEAHEAD_SQL . '=' . $sql;
} elseif (isset($formElement[FE_TYPEAHEAD_LDAP_SERVER])) {
$formElement[FE_TYPEAHEAD_LDAP_SERVER] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_SERVER);
$formElement[FE_TYPEAHEAD_LDAP_BASE_DN] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_BASE_DN);
$formElement[FE_TYPEAHEAD_LDAP_SEARCH] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_SEARCH);
} elseif (isset($formElement[FE_LDAP_SERVER])) {
$formElement[FE_LDAP_SERVER] = Support::setIfNotSet($formElement, FE_LDAP_SERVER);
$formElement[FE_LDAP_BASE_DN] = Support::setIfNotSet($formElement, FE_LDAP_BASE_DN);
$formElement[FE_LDAP_SEARCH] = Support::setIfNotSet($formElement, FE_LDAP_SEARCH);
$formElement[FE_TYPEAHEAD_LDAP_VALUE_PRINTF] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_VALUE_PRINTF);
$formElement[FE_TYPEAHEAD_LDAP_KEY_PRINTF] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_KEY_PRINTF);
$arr = [
FE_TYPEAHEAD_LDAP_SERVER => $formElement[FE_TYPEAHEAD_LDAP_SERVER],
FE_TYPEAHEAD_LDAP_BASE_DN => $formElement[FE_TYPEAHEAD_LDAP_BASE_DN],
FE_TYPEAHEAD_LDAP_SEARCH => $formElement[FE_TYPEAHEAD_LDAP_SEARCH],
FE_LDAP_SERVER => $formElement[FE_LDAP_SERVER],
FE_LDAP_BASE_DN => $formElement[FE_LDAP_BASE_DN],
FE_LDAP_SEARCH => $formElement[FE_LDAP_SEARCH],
FE_TYPEAHEAD_LDAP_VALUE_PRINTF => $formElement[FE_TYPEAHEAD_LDAP_VALUE_PRINTF],
FE_TYPEAHEAD_LDAP_KEY_PRINTF => $formElement[FE_TYPEAHEAD_LDAP_KEY_PRINTF],
FE_TYPEAHEAD_LIMIT => $formElement[FE_TYPEAHEAD_LIMIT],
......
......@@ -531,6 +531,13 @@ const F_FE_DATA_ERROR = 'data-error';
const F_PARAMETER = 'parameter'; // valid for F_ and FE_
const F_LDAP_SERVER = 'ldapServer';
const F_LDAP_BASE_DN = 'ldapBaseDn';
const F_LDAP_SEARCH = 'ldapSearch';
const F_TYPEAHEAD_LIMIT = 'typeAheadLimit';
const F_TYPEAHEAD_MINLENGTH = 'typeAheadMinLength';
const F_TYPEAHEAD_LDAP_VALUE_PRINTF = 'typeAheadLdapValuePrintf';
const F_TYPEAHEAD_LDAP_KEY_PRINTF = 'typeAheadLdapKeyPrintf';
// FORM_ELEMENT_STATI
const FE_MODE_SHOW = 'show';
......@@ -611,14 +618,16 @@ const FE_TEMPLATE_GROUP_CLASS = 'tgClass';
const FE_TEMPLATE_GROUP_DEFAULT_MAX_LENGTH = 5;
const FE_TEMPLATE_GROUP_NAME_PATTERN = '%d';
const FE_BUTTON_CLASS = 'buttonClass';
const FE_TYPEAHEAD_LIMIT = 'typeaheadLimit';
const FE_TYPEAHEAD_MINLENGTH = 'typeaheadMinLength';
const FE_LDAP_SERVER = F_LDAP_SERVER;
const FE_LDAP_BASE_DN = F_LDAP_BASE_DN;
const FE_LDAP_SEARCH = F_LDAP_SEARCH;
const FE_TYPEAHEAD_LIMIT = F_TYPEAHEAD_LIMIT;
const FE_TYPEAHEAD_MINLENGTH = F_TYPEAHEAD_MINLENGTH;
const FE_TYPEAHEAD_SQL = 'typeAheadSql';
const FE_TYPEAHEAD_LDAP_SERVER = 'typeAheadLdapServer';
const FE_TYPEAHEAD_LDAP_BASE_DN = 'typeAheadLdapBaseDn';
const FE_TYPEAHEAD_LDAP_SEARCH = 'typeAheadLdapSearch';
const FE_TYPEAHEAD_LDAP_VALUE_PRINTF = 'typeAheadLdapValuePrintf';
const FE_TYPEAHEAD_LDAP_KEY_PRINTF = 'typeAheadLdapKeyPrintf';
const FE_TYPEAHEAD_LDAP_VALUE_PRINTF = F_TYPEAHEAD_LDAP_VALUE_PRINTF;
const FE_TYPEAHEAD_LDAP_KEY_PRINTF = F_TYPEAHEAD_LDAP_KEY_PRINTF;
const FE_TYPEAHEAD_LDAP = 'typeAheadLdap';
const FE_FILL_STORE_LDAP = 'fillStoreLdap';
const FE_CHARACTER_COUNT_WRAP = 'characterCountWrap';
const RETYPE_FE_NAME_EXTENSION = 'RETYPE';
......
......@@ -80,7 +80,7 @@ class TypeAhead {
if (isset($sipVars[FE_TYPEAHEAD_SQL])) {
$arr = $this->typeAheadSql($sipVars, $this->vars[TYPEAHEAD_API_QUERY]);
} elseif (isset($sipVars[FE_TYPEAHEAD_LDAP_SERVER])) {
} elseif (isset($sipVars[FE_LDAP_SERVER])) {
$ldap = new Ldap();
$arr = $ldap->process($sipVars, $this->vars[TYPEAHEAD_API_QUERY]);
}
......
......@@ -23,9 +23,9 @@ class Ldap {
public function process($config, $query) {
$arr = array();
$ldapServer = $config[FE_TYPEAHEAD_LDAP_SERVER];
$ldapBaseDn = $config[FE_TYPEAHEAD_LDAP_BASE_DN];
$ldapSearch = $config[FE_TYPEAHEAD_LDAP_SEARCH];
$ldapServer = $config[FE_LDAP_SERVER];
$ldapBaseDn = $config[FE_LDAP_BASE_DN];
$ldapSearch = $config[FE_LDAP_SEARCH];
$ldapSearch = str_replace('?', $query, $ldapSearch);
$ldapLimit = $config[FE_TYPEAHEAD_LIMIT];
......@@ -34,6 +34,18 @@ class Ldap {
throw new UserFormException("Unable to connect to LDAP server: $ldapServer", ERROR_LDAP_CONNECT);
}
if ($config[FE_TYPEAHEAD_LDAP_KEY_PRINTF] == '') {
$config[FE_TYPEAHEAD_LDAP_KEY_PRINTF] = $config[FE_TYPEAHEAD_LDAP_VALUE_PRINTF];
}
if ($config[FE_TYPEAHEAD_LDAP_VALUE_PRINTF] == '') {
$config[FE_TYPEAHEAD_LDAP_VALUE_PRINTF] = $config[FE_TYPEAHEAD_LDAP_KEY_PRINTF];
}
if ($config[FE_TYPEAHEAD_LDAP_KEY_PRINTF] == '') {
throw new UserFormException("Missing parameter '" . FE_TYPEAHEAD_LDAP_KEY_PRINTF . "' and/or '" . FE_TYPEAHEAD_LDAP_VALUE_PRINTF);
}
$keyArr = $this->printfPrepare($config[FE_TYPEAHEAD_LDAP_KEY_PRINTF], $keyFormat);
$valueArr = $this->printfPrepare($config[FE_TYPEAHEAD_LDAP_VALUE_PRINTF], $valueFormat);
......@@ -69,9 +81,9 @@ class Ldap {
/**
* Very specific function to prepare the later 'printfResult()'.
*
* @param $fmtComplete
* @param $fmtFirst
* @return mixed
* @param $fmtComplete printf format string with all args.
* @param $fmtFirst returns the first part of $fmtComplete - the printf format string without any args.
* @return array Array with all requested keynames from $fmtComplete
* @throws CodeException
* @throws UserFormException
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment