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 ...@@ -862,31 +862,46 @@ parameter
* Comments: lines starting with a '#' are treated as a comment and will not be parsed. * Comments: lines starting with a '#' are treated as a comment and will not be parsed.
+------------------------+--------+----------------------------------------------------------------------------------------------------------+ +--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| Name | Type | Description | | Name | Type | Description |
+========================+========+==========================================================================================================+ +==========================+========+==========================================================================================================+
| maxVisiblePill | int | Show pills upto <maxVisiblePill> as button, all further in a dropdown menu. Eg.: maxVisiblePill=3 | | 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 | | 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. | | classPill | string | HTML div with given class, surrounding the `pill` title line. |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+ +--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| classBody | string | HTML div with given class, surrounding all *FormElement*. | | classBody | string | HTML div with given class, surrounding all *FormElement*. |
+------------------------+--------+----------------------------------------------------------------------------------------------------------+ +--------------------------+--------+----------------------------------------------------------------------------------------------------------+
| submitButtonText | string | Show save button, with the <submitButtonText> at the bottom of the form | | 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 | | 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-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-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-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 | | 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' + | 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: * Example:
...@@ -1398,9 +1413,9 @@ Type Ahead ...@@ -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 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 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*: * *FormElement.parameter*:
...@@ -1410,6 +1425,11 @@ the server, the lookup will be performed and the result is displayed as the drop ...@@ -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 Depending of the `typeahead` setup, the given FormElement will contain the displayed `value` or `key` (if a key/value dict is
configured). 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 SQL
;;; ;;;
...@@ -1427,9 +1447,11 @@ LDAP ...@@ -1427,9 +1447,11 @@ LDAP
* *FormElement.parameter*: * *FormElement.parameter*:
* *typeAheadLdapServer* = FQDN of the searched server. E.g.: `directory.uzh.ch` * *typeAheadLdap* This entry activates the *LDAP* typeahead functionality.
* *typeAheadLdapBaseDn* = Base DN. E.g.: `ou=Addressbook,dc=uzh,dc=ch` * *ldapServer* = FQDN of the searched server. E.g.: `directory.uzh.ch`
* *typeAheadLdapSearch* = LDAP search expression. E.g.: `(|(cn=*?*)(mail=*?*)(ou=*?*)(roomNumber=*?*)(telephoneNumber=*?*))` * *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 * *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` 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` * *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'); ...@@ -19,15 +19,14 @@ require_once(__DIR__ . '/../qfq/Constants.php');
* Return JSON encoded answer * Return JSON encoded answer
* *
*/ */
try { try {
$qfq = new \qfq\TypeAhead(); $qfq = new \qfq\TypeAhead();
$answer = $qfq->process(); $answer = $qfq->process();
} catch (\Exception $e) { } 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"); header("Content-Type: application/json");
......
...@@ -382,6 +382,10 @@ abstract class AbstractBuildForm { ...@@ -382,6 +382,10 @@ abstract class AbstractBuildForm {
// Preparation for Log, Debug // Preparation for Log, Debug
$this->store->setVar(SYSTEM_FORM_ELEMENT, Logger::formatFormElementName($fe), STORE_SYSTEM); $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'. // for Upload FormElements, it's necessary to precalculate an optional given 'slaveId'.
if ($fe[FE_TYPE] === FE_TYPE_UPLOAD) { if ($fe[FE_TYPE] === FE_TYPE_UPLOAD) {
Support::setIfNotSet($fe, FE_SLAVE_ID); Support::setIfNotSet($fe, FE_SLAVE_ID);
...@@ -461,6 +465,24 @@ abstract class AbstractBuildForm { ...@@ -461,6 +465,24 @@ abstract class AbstractBuildForm {
return $html; 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. * Check if there is an explicit 'autofocus' definition in at least one FE.
* Found: do nothing, it will be rendered at the correct position. * Found: do nothing, it will be rendered at the correct position.
...@@ -824,17 +846,17 @@ abstract class AbstractBuildForm { ...@@ -824,17 +846,17 @@ abstract class AbstractBuildForm {
if (isset($formElement[FE_TYPEAHEAD_SQL])) { if (isset($formElement[FE_TYPEAHEAD_SQL])) {
$sql = $this->checkSqlAppendLimit($formElement[FE_TYPEAHEAD_SQL], $formElement[FE_TYPEAHEAD_LIMIT]); $sql = $this->checkSqlAppendLimit($formElement[FE_TYPEAHEAD_SQL], $formElement[FE_TYPEAHEAD_LIMIT]);
$urlParam = FE_TYPEAHEAD_SQL . '=' . $sql; $urlParam = FE_TYPEAHEAD_SQL . '=' . $sql;
} elseif (isset($formElement[FE_TYPEAHEAD_LDAP_SERVER])) { } elseif (isset($formElement[FE_LDAP_SERVER])) {
$formElement[FE_TYPEAHEAD_LDAP_SERVER] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_SERVER); $formElement[FE_LDAP_SERVER] = Support::setIfNotSet($formElement, FE_LDAP_SERVER);
$formElement[FE_TYPEAHEAD_LDAP_BASE_DN] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_BASE_DN); $formElement[FE_LDAP_BASE_DN] = Support::setIfNotSet($formElement, FE_LDAP_BASE_DN);
$formElement[FE_TYPEAHEAD_LDAP_SEARCH] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_SEARCH); $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_VALUE_PRINTF] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_VALUE_PRINTF);
$formElement[FE_TYPEAHEAD_LDAP_KEY_PRINTF] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_KEY_PRINTF); $formElement[FE_TYPEAHEAD_LDAP_KEY_PRINTF] = Support::setIfNotSet($formElement, FE_TYPEAHEAD_LDAP_KEY_PRINTF);
$arr = [ $arr = [
FE_TYPEAHEAD_LDAP_SERVER => $formElement[FE_TYPEAHEAD_LDAP_SERVER], FE_LDAP_SERVER => $formElement[FE_LDAP_SERVER],
FE_TYPEAHEAD_LDAP_BASE_DN => $formElement[FE_TYPEAHEAD_LDAP_BASE_DN], FE_LDAP_BASE_DN => $formElement[FE_LDAP_BASE_DN],
FE_TYPEAHEAD_LDAP_SEARCH => $formElement[FE_TYPEAHEAD_LDAP_SEARCH], FE_LDAP_SEARCH => $formElement[FE_LDAP_SEARCH],
FE_TYPEAHEAD_LDAP_VALUE_PRINTF => $formElement[FE_TYPEAHEAD_LDAP_VALUE_PRINTF], FE_TYPEAHEAD_LDAP_VALUE_PRINTF => $formElement[FE_TYPEAHEAD_LDAP_VALUE_PRINTF],
FE_TYPEAHEAD_LDAP_KEY_PRINTF => $formElement[FE_TYPEAHEAD_LDAP_KEY_PRINTF], FE_TYPEAHEAD_LDAP_KEY_PRINTF => $formElement[FE_TYPEAHEAD_LDAP_KEY_PRINTF],
FE_TYPEAHEAD_LIMIT => $formElement[FE_TYPEAHEAD_LIMIT], FE_TYPEAHEAD_LIMIT => $formElement[FE_TYPEAHEAD_LIMIT],
......
...@@ -531,6 +531,13 @@ const F_FE_DATA_ERROR = 'data-error'; ...@@ -531,6 +531,13 @@ const F_FE_DATA_ERROR = 'data-error';
const F_PARAMETER = 'parameter'; // valid for F_ and FE_ 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 // FORM_ELEMENT_STATI
const FE_MODE_SHOW = 'show'; const FE_MODE_SHOW = 'show';
...@@ -611,14 +618,16 @@ const FE_TEMPLATE_GROUP_CLASS = 'tgClass'; ...@@ -611,14 +618,16 @@ const FE_TEMPLATE_GROUP_CLASS = 'tgClass';
const FE_TEMPLATE_GROUP_DEFAULT_MAX_LENGTH = 5; const FE_TEMPLATE_GROUP_DEFAULT_MAX_LENGTH = 5;
const FE_TEMPLATE_GROUP_NAME_PATTERN = '%d'; const FE_TEMPLATE_GROUP_NAME_PATTERN = '%d';
const FE_BUTTON_CLASS = 'buttonClass'; const FE_BUTTON_CLASS = 'buttonClass';
const FE_TYPEAHEAD_LIMIT = 'typeaheadLimit'; const FE_LDAP_SERVER = F_LDAP_SERVER;
const FE_TYPEAHEAD_MINLENGTH = 'typeaheadMinLength'; 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_SQL = 'typeAheadSql';
const FE_TYPEAHEAD_LDAP_SERVER = 'typeAheadLdapServer'; const FE_TYPEAHEAD_LDAP_VALUE_PRINTF = F_TYPEAHEAD_LDAP_VALUE_PRINTF;
const FE_TYPEAHEAD_LDAP_BASE_DN = 'typeAheadLdapBaseDn'; const FE_TYPEAHEAD_LDAP_KEY_PRINTF = F_TYPEAHEAD_LDAP_KEY_PRINTF;
const FE_TYPEAHEAD_LDAP_SEARCH = 'typeAheadLdapSearch'; const FE_TYPEAHEAD_LDAP = 'typeAheadLdap';
const FE_TYPEAHEAD_LDAP_VALUE_PRINTF = 'typeAheadLdapValuePrintf'; const FE_FILL_STORE_LDAP = 'fillStoreLdap';
const FE_TYPEAHEAD_LDAP_KEY_PRINTF = 'typeAheadLdapKeyPrintf';
const FE_CHARACTER_COUNT_WRAP = 'characterCountWrap'; const FE_CHARACTER_COUNT_WRAP = 'characterCountWrap';
const RETYPE_FE_NAME_EXTENSION = 'RETYPE'; const RETYPE_FE_NAME_EXTENSION = 'RETYPE';
......
...@@ -80,7 +80,7 @@ class TypeAhead { ...@@ -80,7 +80,7 @@ class TypeAhead {
if (isset($sipVars[FE_TYPEAHEAD_SQL])) { if (isset($sipVars[FE_TYPEAHEAD_SQL])) {
$arr = $this->typeAheadSql($sipVars, $this->vars[TYPEAHEAD_API_QUERY]); $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(); $ldap = new Ldap();
$arr = $ldap->process($sipVars, $this->vars[TYPEAHEAD_API_QUERY]); $arr = $ldap->process($sipVars, $this->vars[TYPEAHEAD_API_QUERY]);
} }
......
...@@ -23,9 +23,9 @@ class Ldap { ...@@ -23,9 +23,9 @@ class Ldap {
public function process($config, $query) { public function process($config, $query) {
$arr = array(); $arr = array();
$ldapServer = $config[FE_TYPEAHEAD_LDAP_SERVER]; $ldapServer = $config[FE_LDAP_SERVER];
$ldapBaseDn = $config[FE_TYPEAHEAD_LDAP_BASE_DN]; $ldapBaseDn = $config[FE_LDAP_BASE_DN];
$ldapSearch = $config[FE_TYPEAHEAD_LDAP_SEARCH]; $ldapSearch = $config[FE_LDAP_SEARCH];
$ldapSearch = str_replace('?', $query, $ldapSearch); $ldapSearch = str_replace('?', $query, $ldapSearch);
$ldapLimit = $config[FE_TYPEAHEAD_LIMIT]; $ldapLimit = $config[FE_TYPEAHEAD_LIMIT];
...@@ -34,6 +34,18 @@ class Ldap { ...@@ -34,6 +34,18 @@ class Ldap {
throw new UserFormException("Unable to connect to LDAP server: $ldapServer", ERROR_LDAP_CONNECT); 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); $keyArr = $this->printfPrepare($config[FE_TYPEAHEAD_LDAP_KEY_PRINTF], $keyFormat);
$valueArr = $this->printfPrepare($config[FE_TYPEAHEAD_LDAP_VALUE_PRINTF], $valueFormat); $valueArr = $this->printfPrepare($config[FE_TYPEAHEAD_LDAP_VALUE_PRINTF], $valueFormat);
...@@ -69,9 +81,9 @@ class Ldap { ...@@ -69,9 +81,9 @@ class Ldap {
/** /**
* Very specific function to prepare the later 'printfResult()'. * Very specific function to prepare the later 'printfResult()'.
* *
* @param $fmtComplete * @param $fmtComplete printf format string with all args.
* @param $fmtFirst * @param $fmtFirst returns the first part of $fmtComplete - the printf format string without any args.
* @return mixed * @return array Array with all requested keynames from $fmtComplete
* @throws CodeException * @throws CodeException
* @throws UserFormException * @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