From e8095636b56a3dfc213b93f0ae88819387cc84d8 Mon Sep 17 00:00:00 2001 From: Benjamin Renard Date: Tue, 19 May 2020 17:55:55 +0200 Subject: [PATCH] Allow multiple type of objects in LSselect & LSattr_html :: select_object and globally rework and improve LSrelation consequently --- src/css/default/LSselect.css | 26 + .../class/class.LSattr_html_select_object.php | 390 ++++-- .../class.LSformElement_select_object.php | 131 +- src/includes/class/class.LSldapObject.php | 36 +- src/includes/class/class.LSrelation.php | 1150 ++++++++++++----- src/includes/class/class.LSsearchEntry.php | 8 - src/includes/class/class.LSselect.php | 450 ++++++- .../js/LSformElement_select_object_field.js | 75 +- src/includes/js/LSrelation.js | 12 +- src/includes/js/LSselect.js | 76 +- src/includes/routes.php | 92 +- .../default/LSformElement_select_object.tpl | 6 +- .../LSformElement_select_object_field.tpl | 4 +- src/templates/default/select.tpl | 21 +- src/templates/default/select_table.tpl | 14 +- 15 files changed, 1829 insertions(+), 662 deletions(-) diff --git a/src/css/default/LSselect.css b/src/css/default/LSselect.css index 71289f33..4c977dba 100644 --- a/src/css/default/LSselect.css +++ b/src/css/default/LSselect.css @@ -42,3 +42,29 @@ div.LSselect_search { div.LSobject-select { width: 620px; } + +/* + * Selectable object types tabs + */ +ul.LSselect_selectable_object_types { + list-style-type: none; + padding: 0 0 4px 0; + margin: 1em; + margin-bottom: 0; + border-bottom: 1px solid #52BCE5; +} + +ul.LSselect_selectable_object_types li { + color: #fff; + background-color: #52BCE5; + -moz-border-radius: 3px 3px 0px 0px; + border-radius: 3px 3px 0px 0px; + padding: 4px; + display: inline; + margin-right: 1px; + cursor: pointer; +} + +ul.LSselect_selectable_object_types li.current { + background-color: #0072B8; +} diff --git a/src/includes/class/class.LSattr_html_select_object.php b/src/includes/class/class.LSattr_html_select_object.php index 34f1411b..c0089f7b 100644 --- a/src/includes/class/class.LSattr_html_select_object.php +++ b/src/includes/class/class.LSattr_html_select_object.php @@ -54,7 +54,6 @@ class LSattr_html_select_object extends LSattr_html{ $element -> setValue($values); } } - $element -> setSelectableObject($this -> getConfig('html_options.selectable_object.object_type')); return $element; } @@ -73,146 +72,312 @@ class LSattr_html_select_object extends LSattr_html{ } /** - * Retourne un tableau des valeurs de l'attribut à partir des valeurs du formulaire + * Check and return selectable objects configuration and eventually instanciate + * it if &instanciate * - * @param[in] mixed Tableau des valeurs du formulaire + * @param[in] boolean &$instanciated_objects reference If this reference point to an array, each valid + * selectable object type will be instanciated in this + * array with object type name as key. * * @author Benjamin Renard * - * @retval array Tableau des valeurs de l'attribut + * @retval array|false Selectable objects configuration or False on error. */ - public function getValuesFromFormValues($values=NULL) { - $conf = $this -> getConfig('html_options.selectable_object'); - if (is_array($conf) && is_array($values)) { - $retValues = array(); + public function getSelectableObjectsConfig(&$instanciated_objects) { + $confs = $this -> getConfig('html_options.selectable_object'); + if (!is_array($confs)) { + self :: log_debug('getSelectableObjectsConfig(): html_options.selectable_object not properly configured'); + return false; + } + + // Make sure we have an array or configured selectable objects + if (isset($confs['object_type'])) { + $confs = array($confs); + } + + // Return confs + $ret_confs = array(); + + // For each configured object types: + // - check we have the minimal configuration (object_type & value_attribute) + // - check we to not have multiple conf for the same object type + // - load object type + // - implement an object of this type (if is_array($instanciated_objects)) + // - if value are from attributes, check this attribute exists + foreach ($confs as $conf) { if (!isset($conf['object_type'])) { - LSerror :: addErrorCode('LSattr_html_select_object_01',$this -> name); - return; + LSerror :: addErrorCode( + 'LSattr_html_select_object_01', + array( + 'attr' => $this -> name, + 'parameter' => 'object_type', + ) + ); + return false; } if (!isset($conf['value_attribute'])) { - LSerror :: addErrorCode('LSattr_html_select_object_02',$this -> name); - return; + LSerror :: addErrorCode( + 'LSattr_html_select_object_01', + array( + 'attr' => $this -> name, + 'parameter' => 'value_attribute', + ) + ); + return false; } - if (!LSsession :: loadLSobject($conf['object_type'])) { - return; + if (array_key_exists($conf['object_type'], $ret_confs)) { + LSerror :: addErrorCode('LSattr_html_select_object_04', array('type' => $conf['object_type'], 'attr' => $this -> name)); + return false; } + $object_type = $conf['object_type']; - $obj=new $conf['object_type'](); - foreach($values as $dn => $name) { - if ($obj -> loadData($dn)) { - $val = ''; - if(($conf['value_attribute']=='dn')||($conf['value_attribute']=='%{dn}')) { - $val = $dn; - } - else { - if (!isset($obj->attrs[$conf['value_attribute']])) { - LSerror :: addErrorCode('LSattr_html_select_object_02',$this -> name); - return; - } - $val = $obj -> getValue($conf['value_attribute']); - $val = $val[0]; - } - if (empty($val)) { - continue; - } - $retValues[] = $val; + if (!LSsession :: loadLSobject($object_type)) + return false; + + if (is_array($instanciated_objects)) + $instanciated_objects[$object_type] = new $object_type(); + + if (!($conf['value_attribute']=='dn') && !($conf['value_attribute']=='%{dn}')) { + if (!$object_type :: hasAttr($conf['value_attribute'])) { + LSerror :: addErrorCode( + 'LSattr_html_select_object_02', + array( + 'attr' => $this -> name, + 'object_type' => $conf['object_type'], + 'value_attribute' => $conf['value_attribute'], + ) + ); + return false; } } - return $retValues; + + // Handle other parameters + $conf['display_name_format'] = LSconfig :: get('display_name_format', null, null, $conf); + $conf['onlyAccessible'] = LSconfig :: get('onlyAccessible', false, 'bool', $conf); + $conf['filter'] = LSconfig :: get('filter', null, null, $conf); + + $ret_confs[$object_type] = $conf; } - return; + return $ret_confs; + } + + + /** + * Return an array of selected objects with DN as key and as value, an array with object name (key name) + * and type (key object_type). + * + * @param[in] mixed $values array|null Array of the input values () + * @param[in] boolean $fromDNs boolean If true, considered provided values as DNs (default: false) + * @param[in] boolean $retreiveAttrValues boolean If true, attribute values will be returned instead + * of selected objects info (default: false) + * + * @author Benjamin Renard + * + * @retval array|false Array of selected objects with DN as key and object info as value or array + * of attribute values if $retreiveAttrValues==true or False on error. + */ + public function getFormValues($values=NULL, $fromDNs=false, $retreiveAttrValues=false) { + self :: log_debug("getFormValues(): input values=".varDump($values)); + // Check parameters consistency + if ($retreiveAttrValues && !$fromDNs) { + self :: log_fatal('getFormValues(): $fromDNs must be true if $retreiveAttrValues==true'); + return false; + } + if (!is_array($values)) { + self :: log_warning('getFormValues(): $values is not array'); + return false; + } + + // Retreive/check selectable objects config + $objs = array(); + $confs = $this -> getSelectableObjectsConfig($objs); + if (!is_array($confs) || empty($confs)) { + self :: log_warning('getFormValues(): invalid selectable objects config'); + return false; + } + + $selected_objects = array(); + $unrecognizedValues = array(); + $found_values = array(); + foreach ($confs as $conf) { + foreach($values as $value) { + // If we already mark its value as unrecognized, pass + if (in_array($value, $unrecognizedValues)) + continue; + + // Ignore empty value + if (empty($value)) + continue; + + // Determine value attribute: DN/attribute valued (or force form DNs) + if(($conf['value_attribute']=='dn') || ($conf['value_attribute']=='%{dn}') || $fromDNs) { + // Construct resulting list from DN values + if ($conf['onlyAccessible']) { + if (!LSsession :: canAccess($conf['object_type'], $value)) { + self :: log_debug("getFormValues(): ".$conf['object_type']."($value): not accessible, pass"); + continue; + } + } + + // Load object data (with custom filter if defined) + if(!$objs[$conf['object_type']] -> loadData($value, $conf['filter'])) { + self :: log_debug("getFormValues(): ".$conf['object_type']."($value): not found, pass"); + continue; + } + self :: log_debug("getFormValues(): ".$conf['object_type']."($value): found"); + + // Check if it's the first this value match with an object + if (isset($found_values[$value])) { + // DN match with multiple object type + LSerror :: addErrorCode('LSattr_html_select_object_03',array('val' => $value, 'attribute' => $this -> name)); + $unrecognizedValues[] = $value; + unset($selected_objects[$found_values[$value]]); + break; + } + $found_values[$value] = $value; + + if ($retreiveAttrValues) { + // Retreive attribute value case: $selected_objects[dn] = attribute value + if(($conf['value_attribute']=='dn') || ($conf['value_attribute']=='%{dn}')) { + $selected_objects[$value] = $value; + } + else { + $val = $objs[$conf['object_type']] -> getValue($conf['value_attribute']); + if (!empty($val)) { + $selected_objects[$value] = $val[0]; + } + else { + LSerror :: addErrorCode( + 'LSattr_html_select_object_06', + array( + 'name' => $objs[$conf['object_type']] -> getDisplayName($conf['display_name_format']), + 'attr' => $this -> name + ) + ); + } + } + } + else { + // General case: $selected_objects[dn] = array(name + object_type) + $selected_objects[$value] = array( + 'name' => $objs[$conf['object_type']] -> getDisplayName($conf['display_name_format']), + 'object_type' => $conf['object_type'], + ); + self :: log_debug("getFormValues(): ".$conf['object_type']."($value): ".varDump($selected_objects[$value])); + } + } + else { + // Construct resulting list from attributes values + $filter = Net_LDAP2_Filter::create($conf['value_attribute'], 'equals', $value); + if (isset($conf['filter'])) + $filter = LSldap::combineFilters('and', array($filter, $conf['filter'])); + $sparams = array(); + $sparams['onlyAccessible'] = $conf['onlyAccessible']; + $listobj = $objs[$conf['object_type']] -> listObjectsName( + $filter, + NULL, + $sparams, + $conf['display_name_format'] + ); + if (count($listobj)==1) { + if (isset($found_values[$value])) { + // Value match with multiple object type + LSerror :: addErrorCode('LSattr_html_select_object_03',array('val' => $value, 'attribute' => $this -> name)); + $unrecognizedValues[] = $value; + unset($selected_objects[$found_values[$value]]); + break; + } + $dn = key($listobj); + $selected_objects[$dn] = array( + 'name' => $listobj[$dn], + 'object_type' => $conf['object_type'], + ); + $found_values[$value] = $dn; + } + else if(count($listobj) > 1) { + LSerror :: addErrorCode('LSattr_html_select_object_03',array('val' => $value, 'attribute' => $this -> name)); + if (!in_array($value, $unrecognizedValues)) + $unrecognizedValues[] = $value; + break; + } + } + } + } + + // Check if all values have been found (or already considered as unrecognized) + foreach ($values as $value) { + if (!isset($found_values[$value]) && !in_array($value, $unrecognizedValues)) { + self :: log_debug("getFormValues(): value '$value' not recognized"); + $unrecognizedValues[] = $value; + } + } + + // Retreive attribute values case: return forged array values (list of attribute values) + if ($retreiveAttrValues) + return array_values($selected_objects); + + // General case + self :: log_debug("getFormValues(): unrecognizedValues=".varDump($unrecognizedValues)); + $this -> unrecognizedValues = $unrecognizedValues; + + self :: log_debug("getFormValues(): final values=".varDump($selected_objects)); + return $selected_objects; } /** - * Retourne un tableau des objects selectionnés + * Get LSselect ID for this attribute * - * @param[in] mixed $values Tableau des valeurs de l'attribut - * @param[in] boolean $fromDNs True si les valeurs passées en paramètre sont des DNs + * @return string The LSselect ID for this attribute + */ + public function getLSselectId() { + $id = ""; + if ($this -> attribute -> ldapObject -> isNew()) + $id .= $this -> attribute -> ldapObject -> getType(); + else + $id .= $this -> attribute -> ldapObject -> getDn(); + $id .= "|".$this -> name; + return $id; + } + + + /** + * Return array of atttribute values form array of form values + * + * @param[in] mixed Array of form values * * @author Benjamin Renard * - * @retval array Tableau associatif des objects selectionés avec en clé - * le DN et en valeur ce qui sera affiché. + * @retval array|false Array of attribute values or False on error. */ - public function getFormValues($values=NULL, $fromDNs=false) { - $conf = $this -> getConfig('html_options.selectable_object'); - if (is_array($conf) && is_array($values)) { - if (!isset($conf['object_type'])) { - LSerror :: addErrorCode('LSattr_html_select_object_01',$this -> name); - return; - } - - if (!isset($conf['value_attribute'])) { - LSerror :: addErrorCode('LSattr_html_select_object_02',$this -> name); - return; - } - - if (!LSsession :: loadLSobject($conf['object_type'])) { - return; - } - - $retInfos = array(); - $DNs=array(); - - $obj = new $conf['object_type'](); - if(($conf['value_attribute']=='dn')||($conf['value_attribute']=='%{dn}')||$fromDNs) { - $DNs=$values; - foreach($DNs as $dn) { - if($obj -> loadData($dn)) { - $retInfos[$dn] = $obj -> getDisplayName((isset($conf['display_name_format'])?$conf['display_name_format']:null)); - } - } - } - else { - if (!is_array(LSconfig::get('LSobjects.'.$conf['object_type'].'.attrs.'.$conf['value_attribute']))) { - LSerror :: addErrorCode('LSattr_html_select_object_02', $this -> name); - return; - } - $unrecognizedValues=array(); - foreach($values as $val) { - if (!empty($val)) { - $filter=Net_LDAP2_Filter::create($conf['value_attribute'],'equals',$val); - if (isset($conf['filter'])) $filter = LSldap::combineFilters('and',array($filter,$conf['filter'])); - $sparams=array(); - $sparams['onlyAccessible'] = (isset($conf['onlyAccessible'])?$conf['onlyAccessible']:False); - $listobj = $obj -> listObjectsName($filter, NULL, $sparams, (isset($conf['display_name_format'])?$conf['display_name_format']:false)); - if (count($listobj)==1) { - foreach($listobj as $dn => $name) { - $DNs[]=$dn; - $retInfos[$dn] = $name; - } - } - else { - $unrecognizedValues[]=$val; - if(count($listobj)>1) { - LSerror :: addErrorCode('LSattr_html_select_object_03',array('val' => $val, 'attribute' => $this -> name)); - } - } - } - } - $this -> unrecognizedValues=$unrecognizedValues; - } - $_SESSION['LSselect'][$conf['object_type']] = $DNs; - return $retInfos; + public function getValuesFromFormValues($values=NULL) { + if (is_array($values)) { + return $this -> getFormValues(array_keys($values), true, true); } return false; } - /** - * Retourne un tableau des valeurs de l'attribut à partir de la variable session + * Return an array of selected objects with DN as key and display name as value + * from LSselect * * @author Benjamin Renard * * @retval array Tableau associatif des objects selectionnés avec en clé * le DN et en valeur ce qui sera affiché. */ - public function getValuesFromSession() { - $obj_type = $this -> getConfig('html_options.selectable_object.object_type'); - if ( $obj_type && is_array($_SESSION['LSselect'][$obj_type]) ) { - return $this -> getFormValues($_SESSION['LSselect'][$obj_type], true); + public function getValuesFromLSselect() { + $LSselect_id = $this -> getLSselectId(); + if (LSsession :: loadLSclass('LSselect', null, true) && LSselect :: exists($LSselect_id)) { + $selected_objects = LSselect :: getSelectedObjects($LSselect_id); + self :: log_debug("getValuesFromLSselect(): selected objects retreived from LSselect '$LSselect_id' = ".varDump($selected_objects)); + if (is_array($selected_objects)) { + return $this -> getFormValues( + array_keys($selected_objects), + true + ); + } } return false; } @@ -234,11 +399,20 @@ class LSattr_html_select_object extends LSattr_html{ * Error Codes */ LSerror :: defineError('LSattr_html_select_object_01', -_("LSattr_html_select_object : LSobject type is undefined (attribute : %{attr}).") +_("LSattr_html_select_object : parameter '%{parameter}' is missing (attribute : %{attr}).") ); LSerror :: defineError('LSattr_html_select_object_02', -_("LSattr_html_select_object : the value of the parameter value_attribute in the configuration of the attribute %{attrs} is incorrect. This attribute does not exists.") +_("LSattr_html_select_object : the value of the parameter value_attribute in the configuration of the attribute %{attrs} is incorrect. Object %{object_type} have no attribute %{value_attribute}.") ); LSerror :: defineError('LSattr_html_select_object_03', _("LSattr_html_select_object : more than one object returned corresponding to value %{val} of attribute %{attr}.") ); +LSerror :: defineError('LSattr_html_select_object_04', +_("LSattr_html_select_object : selection of object type %{type} is configured multiple time for attribute %{attr}.") +); +LSerror :: defineError('LSattr_html_select_object_05', +_("LSattr_html_select_object : the value '%{value}' seem to be duplicated in values of the attribute %{attr}.") +); +LSerror :: defineError('LSattr_html_select_object_06', +_("LSattr_html_select_object : selected object %{name} has no attribute %{attr} value, you can't select it.") +); diff --git a/src/includes/class/class.LSformElement_select_object.php b/src/includes/class/class.LSformElement_select_object.php index 10ec167b..a563c8aa 100644 --- a/src/includes/class/class.LSformElement_select_object.php +++ b/src/includes/class/class.LSformElement_select_object.php @@ -56,7 +56,7 @@ class LSformElement_select_object extends LSformElement { public function getDisplay($refresh=NULL){ LSsession :: addCssFile('LSformElement_select_object.css'); if ($refresh) { - $this -> values = $this -> getValuesFromSession(); + $this -> values = $this -> getValuesFromLSselect(); } $return = $this -> getLabelInfos(); @@ -64,7 +64,7 @@ class LSformElement_select_object extends LSformElement { LSsession :: addJSconfigParam( $this -> name, array( - 'object_type' => $this -> selectableObject, + 'LSselect_id' => $this -> attr_html -> getLSselectId(), 'addBtn' => _('Modify'), 'deleteBtns' => _('Delete'), 'up_label' => _('Move up'), @@ -88,23 +88,57 @@ class LSformElement_select_object extends LSformElement { LSsession :: addJSscript('LSformElement_select_object_field.js'); LSsession :: addJSscript('LSformElement_select_object.js'); - if (LSsession :: loadLSclass('LSselect')) { + if (LSsession :: loadLSclass('LSselect') && $this -> initLSselect()) { LSselect :: loadDependenciesDisplay(); } } if ($this -> getParam('html_options.sort', true) && !$this -> getParam('html_options.ordered', false, 'bool')) { - uasort($this -> values,array($this,'_sortTwoValues')); + uasort($this -> values, array($this, '_sortTwoValues')); } $return['html'] = $this -> fetchTemplate(NULL,array( - 'selectableObject' => $this -> selectableObject, 'unrecognizedValues' => $this -> attr_html -> unrecognizedValues, 'unrecognizedValueLabel' => _("%{value} (unrecognized value)") )); return $return; } + /** + * Init LSselect + * + * @retval boolean True if LSselect is initialized, false otherwise + */ + private function initLSselect() { + // Retreive selectable objects configuratio from HTML attr + $objs = null; + $confs = $this -> attr_html -> getSelectableObjectsConfig($objs); + if (!is_array($confs)) { + self :: log_warning($this -> name.": html_options.selectable_object not defined"); + return false; + } + + // Build selectable objects type list as required by LSselect + $select_conf = array(); + foreach ($confs as $obj_type => $conf) { + $select_conf[$obj_type] = array( + 'object_type' => $conf['object_type'], + 'display_name_format' => $conf['display_name_format'], + 'filter' => $conf['filter'], + 'onlyAccessible' => $conf['onlyAccessible'], + ); + } + + // Init LSselect + LSselect :: init( + $this -> attr_html -> getLSselectId(), + $select_conf, + boolval($this -> getParam('multiple', 0, 'int')), + $this -> values + ); + return True; + } + /** * Function use with uasort to sort two values * @@ -121,26 +155,15 @@ class LSformElement_select_object extends LSformElement { $dir=1; } if ($va == $vb) return 0; - $val = strcoll(strtolower($va), strtolower($vb)); + $val = strcoll(strtolower($va['name']), strtolower($vb['name'])); return $val*$dir; } /* * Return the values of the object form the session variable */ - public function getValuesFromSession() { - return $this -> attr_html -> getValuesFromSession(); - } - - /** - * Defined the type of object witch is selectionable - * - * @param[in] $object string The type of object - * - * @retval void - **/ - public function setSelectableObject($object) { - $this -> selectableObject = $object; + public function getValuesFromLSselect() { + return $this -> attr_html -> getValuesFromLSselect(); } /** @@ -163,8 +186,10 @@ class LSformElement_select_object extends LSformElement { * @retval boolean Return True */ public function setValueFromPostData($data) { - LSformElement::setValueFromPostData($data); - $this -> values = $this -> attr_html -> refreshForm($this -> values,true); + parent :: setValueFromPostData($data); + self :: log_debug("setValueFromPostData(): input values=".varDump($this -> values)); + $this -> values = $this -> attr_html -> refreshForm($this -> values, true); + self :: log_debug("setValueFromPostData(): final values=".varDump($this -> values)); return true; } @@ -175,33 +200,43 @@ class LSformElement_select_object extends LSformElement { * * @retval array(dn -> displayName) Found objects */ - public function searchAdd ($pattern) { - if ($this -> getParam('html_options.selectable_object')) { + public function searchAdd($pattern) { + $objs = array(); + $confs = $this -> attr_html -> getSelectableObjectsConfig($objs); + if (!is_array($confs)) + return; + $selectable_objects = array(); + foreach($confs as $object_type => $conf) { $obj_type = $this -> getParam('html_options.selectable_object.object_type'); - if (LSsession :: loadLSobject($obj_type)) { - $obj = new $obj_type(); - $sparams = array(); - $sparams['onlyAccessible'] = $this -> getParam('html_options.selectable_object.onlyAccessible', false, 'bool'); - $ret = $obj -> getSelectArray( - $pattern, - NULL, - $this -> getParam('html_options.selectable_object.display_name_format'), - false, - true, - $this -> getParam('html_options.selectable_object.filter'), - $sparams + $sparams = array(); + $sparams['onlyAccessible'] = $conf['onlyAccessible']; + $objects = $objs[$object_type] -> getSelectArray( + $pattern, + NULL, + $conf['display_name_format'], + false, + true, + $conf['filter'], + $sparams + ); + self :: log_debug($objects); + if (!is_array($objects)) { + self :: log_warning("searchAdd($pattern): error occured looking for matching $object_type objects"); + continue; + } + foreach($objects as $dn => $name) { + $selectable_objects[$dn] = array ( + 'object_type' => $object_type, + 'name' => $name, ); - if (is_array($ret)) { - return $ret; - } } } - return array(); + return $selectable_objects; } /** * This ajax method is used to refresh the value display - * in the form element after the modify window is closed. + * in the form element after the modify LSselect window is closed. * * @param[in] $data The address to the array of data witch will be return by the ajax request * @@ -211,13 +246,15 @@ class LSformElement_select_object extends LSformElement { if ((isset($_REQUEST['attribute'])) && (isset($_REQUEST['objecttype'])) && (isset($_REQUEST['objectdn'])) && (isset($_REQUEST['idform'])) ) { if (LSsession ::loadLSobject($_REQUEST['objecttype'])) { $object = new $_REQUEST['objecttype'](); - $form = $object -> getForm($_REQUEST['idform']); - $field=$form -> getElement($_REQUEST['attribute']); - $val = $field -> getValuesFromSession(); - if ( $val ) { - $data = array( - 'objects' => $val - ); + if ($object -> loadData($_REQUEST['objectdn'])) { + $form = $object -> getForm($_REQUEST['idform']); + $field=$form -> getElement($_REQUEST['attribute']); + $val = $field -> getValuesFromLSselect(); + if ( $val ) { + $data = array( + 'objects' => $val + ); + } } } } diff --git a/src/includes/class/class.LSldapObject.php b/src/includes/class/class.LSldapObject.php index cd7e06ad..70e7126c 100644 --- a/src/includes/class/class.LSldapObject.php +++ b/src/includes/class/class.LSldapObject.php @@ -79,20 +79,30 @@ class LSldapObject extends LSlog_staticLoggerClass { } /** - * Charge les données de l'objet + * Load object data from LDAP * - * Cette methode définis le DN de l'objet et charge les valeurs de attributs de l'objet - * à partir de l'annuaire. + * This method set object DN and load its data from LDAP * * @author Benjamin Renard * - * @param[in] $dn string Le DN de l'objet. + * @param[in] $dn string The object DN + * @param[in] $additional_filter string|Net_LDAP2_Filter|null A custom LDAP filter that LDAP object + * must respect to permit its data loading * - * @retval boolean true si la chargement a réussi, false sinon. + * @retval boolean True if object data loaded, false otherwise */ - public function loadData($dn) { + public function loadData($dn, $additional_filter=null) { $this -> dn = $dn; - $data = LSldap :: getAttrs($dn, $this -> getObjectFilter()); + $filter = $this -> getObjectFilter(); + if ($additional_filter) { + if (!is_a($additional_filter, Net_LDAP2_Filter)) + $additional_filter = Net_LDAP2_Filter :: parse($additional_filter); + $filter = Net_LDAP2_Filter :: combine( + 'and', + array ($filter, $additional_filter) + ); + } + $data = LSldap :: getAttrs($dn, $filter); if(is_array($data) && !empty($data)) { foreach($this -> attrs as $attr_name => $attr) { if( !$this -> attrs[$attr_name] -> loadData( (isset($data[$attr_name])?$data[$attr_name]:NULL) ) ) @@ -1821,6 +1831,18 @@ class LSldapObject extends LSlog_staticLoggerClass { } } + + /** + * Check if object type have a specified attribute + * + * @param[in] $attr_name string The attribute name + * + * @teval boolean True if object type have a attribute of this name, False otherwise + */ + public static function hasAttr($attr_name) { + return array_key_exists($attr_name, LSconfig :: get('LSobjects.'.get_called_class().'.attrs', array())); + } + /** * List IOformats of this object type * diff --git a/src/includes/class/class.LSrelation.php b/src/includes/class/class.LSrelation.php index c71f8ea7..f3182529 100644 --- a/src/includes/class/class.LSrelation.php +++ b/src/includes/class/class.LSrelation.php @@ -20,186 +20,574 @@ ******************************************************************************/ -class LSrelation { +LSsession :: loadLSclass('LSlog_staticLoggerClass'); +class LSrelation extends LSlog_staticLoggerClass { + + // Reference to the LSldapObject private $obj = null; - private $relationName = null; + + // Relation name + private $name = null; + + // Relation config private $config = null; - public function __construct(&$obj,$relationName) { + /** + * LSrelation constructor + * + * An LSrelation object focus on one type of relations of a specific + * object. All non-static method are designed to manipulate this type + * of relation of the object specified at constuct time. + * + * @param[in] &$obj LSldapObject A reference to the LSldapObject + * @param [in] $relationName string The relation name + * + * @retval void + */ + public function __construct(&$obj, $relationName) { $this -> obj =& $obj; - $this -> relationName = $relationName; - if (isset($obj->config['LSrelation'][$relationName]) && is_array($obj->config['LSrelation'][$relationName])) { - $this -> config = $obj->config['LSrelation'][$relationName]; - } - else { - LSerror :: addErrorCode('LSrelations_02',array('relation' => $relationName,'LSobject' => $obj -> getType())); + $this -> name = $relationName; + $this -> config = $obj -> getConfig("LSrelation.$relationName"); + if (!is_array($this -> config) || !$this -> checkConfig()) { + $this -> config = null; + LSerror :: addErrorCode( + 'LSrelations_02', + array( + 'relation' => $relationName, + 'LSobject' => $obj -> getType() + ) + ); } } - public function exists(&$obj=null,$relationName=null) { - if ($obj && $relationName) { - return (isset($obj->config['LSrelation'][$relationName]) && is_array($obj->config['LSrelation'][$relationName])); - } - else { - return is_array($this -> config); + /** + * Return a configuration parameter (or default value) + * + * @param[] $param The configuration parameter + * @param[] $default The default value (default : null) + * @param[] $cast Cast resulting value in specific type (default : disabled) + * + * @retval mixed The configuration parameter value or default value if not set + **/ + public function getConfig($param, $default=null, $cast=null) { + return LSconfig :: get($param, $default, $cast, $this -> config); + } + + /** + * Get relation info + * + * @param[in] $key string The info name + * + * @retval mixed The info value + */ + public function __get($key) { + switch ($key) { + case 'name': + return $this -> name; + case 'LSobject': + case 'linkAttribute': + case 'linkAttributeValue': + case 'linkAttributeOtherValues': + case 'list_function': + case 'getkeyvalue_function': + case 'update_function': + case 'remove_function': + case 'rename_function': + case 'canEdit_function': + case 'canEdit_attribute': + return $this -> getConfig($key); + case 'linkAttributeValues': + $linkAttributeValues = (is_array($this -> linkAttributeOtherValues)?$this -> linkAttributeOtherValues:array()); + if ($this -> linkAttributeValue) + $linkAttributeValues[] = $this -> linkAttributeValue; + return $linkAttributeValues; + case 'relatedEditableAttribute': + return $this -> getConfig( + 'canEdit_attribute', + $this -> getConfig('linkAttribute', false), + ); } } + /** + * Check relation configuration + * + * @retval boolean True if relation is properly configured, False otherwise + */ + public function checkConfig() { + // Check LSobject parameter + if (!$this -> LSobject) { + LSerror :: addErrorCode( + 'LSrelations_07', + array( + 'parameter' => 'LSobject', + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject + ) + ); + return false; + } + + // Load related object type + if (!LSsession :: loadLSobject($this -> LSobject)) { + LSerror :: addErrorCode( + 'LSrelations_04', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject + ) + ); + return false; + } + + // Check if it's a simple relation + if ($this -> linkAttribute && $this -> linkAttributeValue) { + // Check linkAttribute refered to an existing related object type attribute + if (!$this -> LSobject :: hasAttr($this -> linkAttribute)) { + LSerror :: addErrorCode( + 'LSrelations_08', + array( + 'parameter' => 'linkAttribute', + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject + ) + ); + return false; + } + + // Check linkAttributeValue + if ($this -> linkAttributeValue != 'dn' && !$this -> obj -> hasAttr($this -> linkAttributeValue)) { + LSerror :: addErrorCode( + 'LSrelations_08', + array( + 'parameter' => 'linkAttributeValue', + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject + ) + ); + return false; + } + + return true; + } + + // Advanced relation: check all required parameters refered to related objects + // methods + $required_parameters = array( + 'list_function', 'getkeyvalue_function', 'update_function', + 'remove_function', 'rename_function', 'canEdit_function', + ); + foreach($required_parameters as $p) { + // Check parameter is defined + if (!$this -> $p) { + LSerror :: addErrorCode( + 'LSrelations_07', + array( + 'parameter' => $p, + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject + ) + ); + return false; + } + + // Check parameter refered to an existing related object class method + if (!method_exists($this -> LSobject, $this -> $p)) { + LSerror :: addErrorCode( + 'LSrelations_01', + array( + 'parameter' => $p, + 'function' => $this -> $p, + 'LSobject' => $this -> LSobject, + 'relation' => $this -> name, + ) + ); + return false; + } + } + return true; + } + + /** + * Check a relation exist + * + * @param[in] $object_type string The object type + * @param[in] $relation_name string The relation name + * + * @retval boolean True if relation exist, false otherwise + */ + public static function exists($object_type, $relation_name) { + if ($object_type && LSsession :: loadLSobject($object_type)) { + return is_array(LSconfig :: get("LSobjects.$object_type.LSrelation.$relation_name")); + } + return false; + } + + /** + * Get relation name + * + * @retval string The relation name + */ public function getName() { - return $this -> relationName; + return $this -> name; } + /** + * Check if user can edit this relation + * + * @retval boolean True if user can edit this relation, false otherwise + */ public function canEdit() { - return LSsession :: relationCanEdit($this -> obj -> getValue('dn'),$this -> obj -> getType(),$this -> relationName); + return LSsession :: relationCanEdit($this -> obj -> getValue('dn'),$this -> obj -> getType(),$this -> name); } + /** + * Check if user can create a related object + * + * @retval boolean True if user can create a related object, false otherwise + */ public function canCreate() { - return LSsession :: canCreate($this -> config['LSobject']); + return LSsession :: canCreate($this -> LSobject); } - + /** + * List related objects + * + * @retval array|false An array of related objects (LSldapObject), of false in case of error + */ public function listRelatedObjects() { - if (LSsession :: loadLSobject($this -> config['LSobject'])) { - $objRel = new $this -> config['LSobject'](); - if (isset($this -> config['list_function'])) { - if (method_exists($this -> config['LSobject'],$this -> config['list_function'])) { - return call_user_func_array(array($objRel, $this -> config['list_function']), array(&$this -> obj)); - } - LSerror :: addErrorCode('LSrelations_01',array('function' => $this -> config['list_function'], 'action' => _('listing related objects'), 'relation' => $this -> relationName)); - return False; - } - elseif (isset($this -> config['linkAttribute']) && isset($this -> config['linkAttributeValue'])) { - return $objRel -> listObjectsInRelation($this -> obj, $this -> config['linkAttribute'], $this -> obj -> getType(), $this -> getLinkAttributeValues()); - } - else { - LSerror :: addErrorCode('LSrelations_05',array('relation' => $this -> relationName,'LSobject' => $this -> config['LSobject'],'action' => _('listing related objects'))); - } + // Load related object type + if (!LSsession :: loadLSobject($this -> LSobject)) { + LSerror :: addErrorCode( + 'LSrelations_04', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject + ) + ); + return false; } - else { - LSerror :: addErrorCode('LSrelations_04',array('relation' => $this -> relationName,'LSobject' => $this -> config['LSobject'])); - } - return; - } - - public function getLinkAttributeValues() { - if (isset($this -> config['linkAttributeOtherValues'])) { - $linkAttributeValues=$this -> config['linkAttributeOtherValues']; - $linkAttributeValues[]=$this -> config['linkAttributeValue']; - return $linkAttributeValues; - } - else { - return $this -> config['linkAttributeValue']; + + // Instanciate related object + $objRel = new $this -> LSobject(); + + // Use list_function + if ($this -> list_function) { + if (method_exists($this -> LSobject, $this -> list_function)) { + return call_user_func_array( + array($objRel, $this -> list_function), + array(&$this -> obj) + ); + } + LSerror :: addErrorCode( + 'LSrelations_01', + array( + 'parameter' => 'list_function', + 'function' => $this -> list_function, + 'LSobject' => $objRel -> getType(), + 'relation' => $this -> name, + ) + ); + return False; } + + // Use linkAttribute & linkAttributeValue + if ($this -> linkAttribute && $this -> linkAttributeValue) { + return $objRel -> listObjectsInRelation( + $this -> obj, + $this -> linkAttribute, + $this -> obj -> getType(), + $this -> linkAttributeValues + ); + } + + // Configuration problem + LSerror :: addErrorCode( + 'LSrelations_05', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject, + 'action' => _('listing related objects') + ) + ); + return false; } + /** + * Get the value to store to created the relation with $this -> obj + * + * @retval array List of value of the link attribute + */ public function getRelatedKeyValue() { - if (LSsession :: loadLSobject($this -> config['LSobject'])) { - $objRel = new $this -> config['LSobject'](); - if (isset($this -> config['getkeyvalue_function'])) { - if (method_exists($this -> config['LSobject'],$this -> config['getkeyvalue_function'])) { - return call_user_func_array(array($objRel, $this -> config['getkeyvalue_function']), array(&$this -> obj)); - } - LSerror :: addErrorCode('LSrelations_01',array('function' => $this -> config['getkeyvalue_function'], 'action' => _('getting key value'), 'relation' => $this -> relationName)); - } - elseif (isset($this -> config['linkAttribute']) && isset($this -> config['linkAttributeValue'])) { - return $objRel -> getObjectKeyValueInRelation($this -> obj, $this -> obj -> getType(), $this -> config['linkAttributeValue']); - } - else { - LSerror :: addErrorCode('LSrelations_05',array('relation' => $this -> relationName,'LSobject' => $this -> config['LSobject'],'action' => _('getting key value'))); - } + // Load related object type + if (!LSsession :: loadLSobject($this -> LSobject)) { + LSerror :: addErrorCode( + 'LSrelations_04', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject + ) + ); + return false; } - else { - LSerror :: addErrorCode('LSrelations_04',array('relation' => $this -> relationName,'LSobject' => $this -> config['LSobject'])); + + // Instanciate related object + $objRel = new $this -> LSobject(); + + // Use getkeyvalue_function + if ($this -> getkeyvalue_function) { + if (method_exists($this -> LSobject, $this -> getkeyvalue_function)) { + return call_user_func_array( + array($objRel, $this -> getkeyvalue_function), + array(&$this -> obj) + ); + } + LSerror :: addErrorCode( + 'LSrelations_01', + array( + 'parameter' => 'getkeyvalue_function', + 'function' => $this -> getkeyvalue_function, + 'LSobject' => $objRel -> getType(), + 'relation' => $this -> name, + ) + ); + return false; } - return; + + // Use linkAttribute & linkAttributeValue + if ($this -> linkAttribute && $this -> linkAttributeValue) { + return $objRel -> getObjectKeyValueInRelation( + $this -> obj, + $this -> obj -> getType(), + $this -> linkAttributeValue + ); + } + + // Configuration problem + LSerror :: addErrorCode( + 'LSrelations_05', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject, + 'action' => _('getting key value') + ) + ); + return false; } - public function getRelatedEditableAttribute() { - if (isset($this -> config['canEdit_attribute'])) { - return $this -> config['canEdit_attribute']; - } - elseif (isset($this -> config['linkAttribute'])) { - return $this -> config['linkAttribute']; - } - return False; - } - - public function canEditRelationWithObject($objRel) { + /** + * Check if user can edit the relation with the specified object + * + * @param[in] &$objRel LSldapObject A reference to the related object + * + * @retval boolean True if user can edit the relation with the specified object, false otherwise + */ + public function canEditRelationWithObject(&$objRel) { if (!$this -> canEdit()) return; - if (isset($this -> config['canEdit_function'])) { - if (method_exists($objRel,$this -> config['canEdit_function'])) { - return call_user_func(array($objRel, $this -> config['canEdit_function'])); + + // Use canEdit_function + if ($this -> canEdit_function) { + if (method_exists($objRel, $this -> canEdit_function)) { + return call_user_func(array($objRel, $this -> canEdit_function)); } - LSerror :: addErrorCode('LSrelations_01',array('function' => $this -> config['canEdit_function'], 'action' => _('checking right on relation with specific object'), 'relation' => $this -> relationName)); + LSerror :: addErrorCode( + 'LSrelations_01', + array( + 'parameter' => 'canEdit_function', + 'function' => $this -> canEdit_function, + 'LSobject' => $objRel -> getType(), + 'relation' => $this -> name, + ) + ); return False; } - elseif ($this -> getRelatedEditableAttribute()) { - return LSsession :: canEdit($objRel -> getType(),$objRel -> getDn(),$this -> getRelatedEditableAttribute()); - } - else { - LSerror :: addErrorCode('LSrelations_05',array('relation' => $this -> relationName,'LSobject' => $this -> config['LSobject'],'action' => _('checking right on relation with specific object'))); + + // Use related editable attribute + if ($this -> relatedEditableAttribute) { + return LSsession :: canEdit( + $objRel -> getType(), + $objRel -> getDn(), + $this -> relatedEditableAttribute + ); } + + // Configuration problem + LSerror :: addErrorCode( + 'LSrelations_05', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject, + 'action' => _('checking right on relation with specific object') + ) + ); + return false; } - public function removeRelationWithObject($objRel) { - if (isset($this -> config['remove_function'])) { - if (method_exists($this -> config['LSobject'],$this -> config['remove_function'])) { - return call_user_func_array(array($objRel, $this -> config['remove_function']),array(&$this -> obj)); + /** + * Remove relation with the specified object + * + * @param[in] &$objRel LSldapObject A reference to the related object + * + * @retval boolean True if relation removed, false otherwise + */ + public function removeRelationWithObject(&$objRel) { + // Use remove_function + if ($this -> remove_function) { + if (method_exists($this -> LSobject, $this -> remove_function)) { + return call_user_func_array( + array($objRel, $this -> remove_function), + array(&$this -> obj) + ); } - LSerror :: addErrorCode('LSrelations_01',array('function' => $this -> config['remove_function'], 'action' => _('deleting'), 'relation' => $this -> relationName)); + LSerror :: addErrorCode( + 'LSrelations_01', + array( + 'parameter' => 'remove_function', + 'function' => $this -> remove_function, + 'LSobject' => $objRel -> getType(), + 'relation' => $this -> name, + ) + ); return False; } - elseif (isset($this -> config['linkAttribute']) && isset($this -> config['linkAttributeValue'])) { - return $objRel -> deleteOneObjectInRelation($this -> obj, $this -> config['linkAttribute'], $this -> obj -> getType(), $this -> config['linkAttributeValue'], null, $this -> getLinkAttributeValues()); + + // Use linkAttribute & linkAttributeValue + if ($this -> linkAttribute && $this -> linkAttributeValue) { + return $objRel -> deleteOneObjectInRelation($this -> obj, $this -> linkAttribute, $this -> obj -> getType(), $this -> linkAttributeValue, null, $this -> linkAttributeValues); } - else { - LSerror :: addErrorCode('LSrelations_05',array('relation' => $this -> relationName,'LSobject' => $this -> config['LSobject'],'action' => _('removing relation with specific object'))); - } - return; + + // Configuration problem + LSerror :: addErrorCode( + 'LSrelations_05', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject, + 'action' => _('removing relation with specific object') + ) + ); + return false; } - public function renameRelationWithObject($objRel,$oldKeyValue) { - if (isset($this -> config['rename_function'])) { - if (method_exists($objRel,$this -> config['rename_function'])) { - return call_user_func_array(array($objRel, $this -> config['rename_function']), array(&$this -> obj, $oldKeyValue)); + /** + * Rename relation with the specified object + * + * @param[in] &$objRel LSldapObject A reference to the related object + * @param[in] $oldKeyValue string The old key value of the relation + * + * @retval boolean True if relation rename, false otherwise + */ + public function renameRelationWithObject(&$objRel, $oldKeyValue) { + // Use rename_function + if ($this -> rename_function) { + if (method_exists($objRel,$this -> rename_function)) { + return call_user_func_array(array($objRel, $this -> rename_function), array(&$this -> obj, $oldKeyValue)); } - LSerror :: addErrorCode('LSrelations_01',array('function' => $this -> config['rename_function'], 'action' => _('renaming'), 'relation' => $this -> relationName)); + LSerror :: addErrorCode( + 'LSrelations_01', + array( + 'parameter' => 'rename_function', + 'function' => $this -> rename_function, + 'LSobject' => $objRel -> getType(), + 'relation' => $this -> name, + ) + ); return False; } - elseif (isset($this -> config['linkAttribute']) && isset($this -> config['linkAttributeValue'])) { - return $objRel -> renameOneObjectInRelation($this -> obj, $oldKeyValue, $this -> config['linkAttribute'], $this -> obj -> getType(), $this -> config['linkAttributeValue']); + + // Use linkAttribute & linkAttributeValue + if ($this -> linkAttribute && $this -> linkAttributeValue) { + return $objRel -> renameOneObjectInRelation( + $this -> obj, + $oldKeyValue, + $this -> linkAttribute, + $this -> obj -> getType(), + $this -> linkAttributeValue + ); } - else { - LSerror :: addErrorCode('LSrelations_05',array('relation' => $this -> relationName,'LSobject' => $this -> config['LSobject'],'action' => _('checking right on relation with specific object'))); - } - return; + + // Configuration problem + LSerror :: addErrorCode( + 'LSrelations_05', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject, + 'action' => _('checking right on relation with specific object') + ) + ); + return false; } + /** + * Update relation with the specified DN objects list + * + * @param[in] $listDns array Array of DN of the related objects + * + * @retval boolean True if relations updated, false otherwise + */ public function updateRelations($listDns) { - if (LSsession :: loadLSobject($this -> config['LSobject'])) { - $objRel = new $this -> config['LSobject'](); - if (isset($this -> config['update_function'])) { - if (method_exists($objRel,$this -> config['update_function'])) { - return call_user_func_array(array($objRel, $this -> config['update_function']), array(&$this -> obj, $listDns)); - } - LSerror :: addErrorCode('LSrelations_01',array('function' => $this -> config['update_function'], 'action' => _('updating'), 'relation' => $this -> relationName)); - } - elseif (isset($this -> config['linkAttribute']) && isset($this -> config['linkAttributeValue'])) { - return $objRel -> updateObjectsInRelation($this -> obj, $listDns, $this -> config['linkAttribute'], $this -> obj -> getType(), $this -> config['linkAttributeValue'],null,$this -> getLinkAttributeValues()); - } - else { - LSerror :: addErrorCode('LSrelations_05',array('relation' => $this -> relationName,'LSobject' => $this -> config['LSobject'],'action' => _('updating relations'))); - } + // Load related objects type + if (!LSsession :: loadLSobject($this -> LSobject)) { + LSerror :: addErrorCode( + 'LSrelations_04', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject + ) + ); + return false; } - else { - LSerror :: addErrorCode('LSrelations_04',array('relation' => $this -> relationName,'LSobject' => $this -> config['LSobject'])); + + // Instanciate related object + $objRel = new $this -> LSobject(); + + // Use update_function + if ($this -> update_function) { + if (method_exists($objRel, $this -> update_function)) { + return call_user_func_array( + array($objRel, $this -> update_function), + array(&$this -> obj, $listDns) + ); + } + LSerror :: addErrorCode( + 'LSrelations_01', + array( + 'parameter' => 'update_function', + 'function' => $this -> update_function, + 'LSobject' => $objRel -> getType(), + 'relation' => $this -> name, + ) + ); + return false; } - return; + + // Use linkAttribute & linkAttributeValue + if ($this -> linkAttribute && $this -> linkAttributeValue) { + return $objRel -> updateObjectsInRelation( + $this -> obj, + $listDns, + $this -> linkAttribute, + $this -> obj -> getType(), + $this -> linkAttributeValue, + null, + $this -> linkAttributeValues + ); + } + + // Configuration problem + LSerror :: addErrorCode( + 'LSrelations_05', + array( + 'relation' => $this -> name, + 'LSobject' => $this -> LSobject, + 'action' => _('updating relations') + ) + ); + return false; } /* - * Méthode chargeant les dépendances d'affichage + * Load display dependencies * * @retval void */ @@ -218,241 +606,351 @@ class LSrelation { } /* - * Méthode chargeant les informations des LSrelations d'un objet et définissant - * les variables templates pour l'affichage dans une LSview. + * Load LSrelations information of an object to display it on LSview. * - * @param[in] LSldapObject L'objet dont on cherche les LSrelations + * LSrelations information are provided to template by usind LSrelations variable. + * + * @param[in] $object LSldapObject L'objet dont on cherche les LSrelations * * @retval void */ public static function displayInLSview($object) { - if (($object instanceof LSldapObject) && isset($object -> config['LSrelation']) && is_array($object -> config['LSrelation'])) { - $LSrelations=array(); - $LSrelations_JSparams=array(); - foreach($object -> config['LSrelation'] as $relationName => $relationConf) { - if (LSsession :: relationCanAccess($object -> getValue('dn'),$object->getType(),$relationName)) { - $return=array( - 'label' => __($relationConf['label']), - 'LSobject' => $relationConf['LSobject'] - ); + if (!($object instanceof LSldapObject)) + return; - if (isset($relationConf['emptyText'])) { - $return['emptyText'] = __($relationConf['emptyText']); - } - else { - $return['emptyText'] = _('No object.'); - } + if (!is_array($object -> getConfig('LSrelation'))) + return; - $id=rand(); - $return['id']=$id; - $LSrelations_JSparams[$id]=array( - 'emptyText' => $return['emptyText'] - ); - $_SESSION['LSrelation'][$id] = array( - 'relationName' => $relationName, - 'objectType' => $object -> getType(), - 'objectDn' => $object -> getDn(), - ); - $relation = new LSrelation($object, $relationName); - - if ($relation -> canEdit()) { - $return['actions'][] = array( - 'label' => _('Modify'), - 'url' => 'object/'.$relationConf['LSobject'].'/select?multiple=1'.($relation -> getRelatedEditableAttribute()?'&editableAttr='.$relation -> getRelatedEditableAttribute():''), - 'action' => 'modify', - 'class' => 'LSrelation_modify', - ); - } - if ($relation -> canCreate()) { - $return['actions'][] = array( - 'label' => _('New'), - 'url' => 'object/'.$relationConf['LSobject'].'/create?LSrelation='.$relationName.'&relatedLSobject='.$object->getType().'&relatedLSobjectDN='.urlencode($object -> getValue('dn')), - 'action' => 'create', - 'class' => null, - ); - } - - $list = $relation -> listRelatedObjects(); - if (is_array($list)) { - foreach($list as $o) { - $return['objectList'][] = array( - 'text' => $o -> getDisplayName(NULL,true), - 'dn' => $o -> getDn(), - 'canEdit' => $relation -> canEditRelationWithObject($o) - ); - } - } - else { - $return['objectList']=array(); - } - $LSrelations[]=$return; - } + $LSrelations=array(); + $LSrelations_JSparams=array(); + foreach($object -> getConfig('LSrelation') as $relationName => $relationConf) { + // Check user access + if (!LSsession :: relationCanAccess($object -> getValue('dn'), $object->getType(), $relationName)) { + self :: log_debug("User have no access to relation $relationName of ".$object->getType()); + continue; } - self :: loadDependenciesDisplay(); - LStemplate :: assign('LSrelations',$LSrelations); - LSsession :: addJSconfigParam('LSrelations',$LSrelations_JSparams); - } - } + $return=array( + 'label' => __($relationConf['label']), + 'LSobject' => $relationConf['LSobject'] + ); - public static function ajax_refreshSession(&$return) { - if ((isset($_REQUEST['id'])) && (isset($_REQUEST['href'])) ) { - if (isset($_SESSION['LSrelation'][$_REQUEST['id']])) { - $conf = $_SESSION['LSrelation'][$_REQUEST['id']]; - if (LSsession ::loadLSobject($conf['objectType'])) { - $object = new $conf['objectType'](); - if (($object -> loadData($conf['objectDn'])) && (isset($object->config['LSrelation'][$conf['relationName']]))) { - $relation = new LSrelation($object, $conf['relationName']); - $LSobjectInRelation = $object->config['LSrelation'][$conf['relationName']]['LSobject']; - if ($relation -> canEdit()) { - $list = $relation -> listRelatedObjects(); - $_SESSION['LSselect'][$LSobjectInRelation]=array(); - if (is_array($list)) { - foreach($list as $o) { - $_SESSION['LSselect'][$LSobjectInRelation][] = $o -> getDn(); - } - } - $return = array( - 'href' => $_REQUEST['href'], - 'id' => $_REQUEST['id'] - ); - } - else { - LSerror :: addErrorCode('LSsession_11'); - } - } - else { - LSerror :: addErrorCode('LSsession_12'); - } - } - else { - LSerror :: addErrorCode('LSsession_12'); + if (isset($relationConf['emptyText'])) { + $return['emptyText'] = __($relationConf['emptyText']); + } + else { + $return['emptyText'] = _('No object.'); + } + + $id=rand(); + $return['id']=$id; + $LSrelations_JSparams[$id]=array( + 'emptyText' => $return['emptyText'] + ); + $_SESSION['LSrelation'][$id] = array( + 'relationName' => $relationName, + 'objectType' => $object -> getType(), + 'objectDn' => $object -> getDn(), + ); + $relation = new LSrelation($object, $relationName); + + if ($relation -> canEdit()) { + $return['actions'][] = array( + 'label' => _('Modify'), + 'url' => "object/select/$id", + 'action' => 'modify', + 'class' => 'LSrelation_modify', + ); + } + if ($relation -> canCreate()) { + $return['actions'][] = array( + 'label' => _('New'), + 'url' => 'object/'.$relationConf['LSobject'].'/create?LSrelation='.$relationName.'&relatedLSobject='.$object->getType().'&relatedLSobjectDN='.urlencode($object -> getValue('dn')), + 'action' => 'create', + 'class' => null, + ); + } + + $list = $relation -> listRelatedObjects(); + if (is_array($list)) { + foreach($list as $o) { + $return['objectList'][] = array( + 'text' => $o -> getDisplayName(NULL,true), + 'dn' => $o -> getDn(), + 'canEdit' => $relation -> canEditRelationWithObject($o) + ); } } else { - LSerror :: addErrorCode('LSsession_12'); + $return['objectList']=array(); } + $LSrelations[]=$return; } + + self :: loadDependenciesDisplay(); + LStemplate :: assign('LSrelations',$LSrelations); + LSsession :: addJSconfigParam('LSrelations',$LSrelations_JSparams); } - public static function ajax_refreshList(&$data) { - if (isset($_REQUEST['id'])) { - if (isset($_SESSION['LSrelation'][$_REQUEST['id']])) { - $conf = $_SESSION['LSrelation'][$_REQUEST['id']]; - if (LSsession ::loadLSobject($conf['objectType'])) { - $object = new $conf['objectType'](); - if (($object -> loadData($conf['objectDn'])) && (isset($object->config['LSrelation'][$conf['relationName']]))) { - $relation = new LSrelation($object, $conf['relationName']); - $LSobjectInRelation = $object->config['LSrelation'][$conf['relationName']]['LSobject']; - $relationConf = $object->config['LSrelation'][$conf['relationName']]; - if($relation -> updateRelations($_SESSION['LSselect'][$LSobjectInRelation])) { - $list = $relation -> listRelatedObjects(); - if (is_array($list)&&(!empty($list))) { - $data['html']=""; - foreach($list as $o) { - if ($relation -> canEditRelationWithObject($o)) { - $class=' LSrelation_editable'; - } - else { - $class=''; - } - $data['html'].= "
  • getDn()."'>".$o -> getDisplayName(NULL,true)."
  • \n"; - } - } - else { - if (isset($relationConf['emptyText'])) { - $data['html'] = "
  • ".__($relationConf['emptyText'])."
  • \n"; - } - else { - $data['html'] = "
  • "._('No object.')."
  • \n"; - } - } - $data['id'] = $_REQUEST['id']; - } - else { - LSerror :: addErrorCode('LSrelations_03', $conf['relationName']); - } - } - else { - LSerror :: addErrorCode('LSsession_12'); - } + /* + * AJAX methods + */ + + /** + * Helper to check AJAX method call and instanciate corresponding + * LSldapObject and LSrelation objects. + * + * @param[in] &$data array Reference to AJAX returned data array + * @param[in] $additional_parameters array|string|null List of additional required parameter + * + * @retval array|false Array with LSobject and LSrelation + */ + public static function _ajax_check_call(&$data, &$conf, &$object, &$relation, $additional_required_parameters=null) { + $data['success'] = false; + // Check parameters + if (!isset($_REQUEST['id'])) { + self :: log_warning("Parameter 'id' is missing."); + LSerror :: addErrorCode('LSsession_12'); + return false; + } + + // Check additional required parameters + if ($additional_required_parameters) { + if (!is_array($additional_required_parameters)) + $additional_required_parameters = array($additional_required_parameters); + foreach($additional_required_parameters as $p) { + if (!isset($_REQUEST[$p])) { + self :: log_warning("Parameter '$p' is missing."); + LSerror :: addErrorCode('LSsession_12'); + return false; + } + $data[$p] = $_REQUEST[$p]; + } + } + + // Check relation exists in session + if (!isset($_SESSION['LSrelation'][$_REQUEST['id']])) { + self :: log_warning("No relation '".$_REQUEST['id']."' in session"); + return false; + } + + // Load object type + $conf = $_SESSION['LSrelation'][$_REQUEST['id']]; + if (!LSsession ::loadLSobject($conf['objectType'])) { + self :: log_warning("Fail to load '".$conf['objectType']."'"); + return false; + } + $data['id'] = $_REQUEST['id']; + + // Check relation exists + if (!self :: exists($conf['objectType'], $conf['relationName'])) { + self :: log_warning("Relation '".$conf['relationName']."' not found in ".$conf['objectType']." configuration"); + return false; + } + + // Instanciate object and load its data + $object = new $conf['objectType'](); + if (!$object -> loadData($conf['objectDn'])) { + self :: log_warning("Fail to load data of '".$conf['objectDn']."'"); + return false; + } + + // Instanciate relation + $relation = new LSrelation($object, $conf['relationName']); + + // Check user access to it relation + if (!$relation -> canEdit()) { + LSerror :: addErrorCode('LSsession_11'); + return false; + } + + self :: log_debug("_ajax_check_call(): ok"); + return true; + } + + + /** + * Init LSselect for a relation + * + * @param[in] &$data Reference to returned data array + * + * @retval void + */ + public static function ajax_initSelection(&$data) { + $conf = null; + $object = null; + $relation = null; + if (!self :: _ajax_check_call($data, $conf, $object, $relation, 'href')) { + return; + } + + $LSobjectInRelation = $object->getConfig("LSrelation.".$conf['relationName'].".LSobject"); + + // Load LSobject + if(!LSsession :: loadLSclass('LSselect', null, true)) { + return; + } + + // List related objects + $list = $relation -> listRelatedObjects(); + if (!is_array($list)) { + self :: log_warning('Fail to list related objects'); + return; + } + + // Forge selected object list for LSselect + $selected_objects = array(); + foreach($list as $o) { + $selected_objects[$o -> getDn()] = array( + 'object_type' => $o -> getType(), + 'editableAttr' => $relation -> relatedEditableAttribute, + ); + } + + // Init LSselect + LSselect :: init( + $_REQUEST['id'], + array ( + $conf['objectType'] => array( + 'object_type' => $conf['objectType'] + ) + ), + true, + $selected_objects + ); + + // Set success + $data['success'] = true; + } + + /** + * Update related object from LSselect result + * + * @param[in] &$data Reference to returned data array + * + * @retval void + */ + public static function ajax_updateFromSelection(&$data) { + $conf = null; + $object = null; + $relation = null; + if (!self :: _ajax_check_call($data, $conf, $object, $relation)) { + return; + } + + $LSobjectInRelation = $object->getConfig("LSrelation.".$conf['relationName'].".LSobject"); + $relationConf = $object->getConfig("LSrelation.".$conf['relationName']); + + // Load LSselect + if(!LSsession :: loadLSclass('LSselect', null, true)) { + return; + } + + // Retreive selected object from LSselect + $selected_objects = LSselect :: getSelectedObjects($_REQUEST['id']); + if (!is_array($selected_objects)) { + self :: log_warning("Fail to retreive selected object from LSselect"); + return; + } + self :: log_debug('Selected objects: '.varDump($selected_objects)); + + // Update related objects + if (!$relation -> updateRelations(array_keys($selected_objects))) { + LSerror :: addErrorCode('LSrelations_03', $conf['relationName']); + self :: log_warning("Fail to update objects in relation"); + return; + } + self :: log_debug('Related objects updated'); + + // List related objects + $list = $relation -> listRelatedObjects(); + if (is_array($list) && !empty($list)) { + $data['html']=""; + foreach($list as $o) { + if ($relation -> canEditRelationWithObject($o)) { + $class=' LSrelation_editable'; } else { - LSerror :: addErrorCode('LSsession_12'); + $class=''; } - } - else { - LSerror :: addErrorCode('LSsession_12'); + $data['html'].= "
  • getDn()."'>".$o -> getDisplayName(NULL,true)."
  • \n"; } } + else { + if (isset($relationConf['emptyText'])) { + $data['html'] = "
  • ".__($relationConf['emptyText'])."
  • \n"; + } + else { + $data['html'] = "
  • "._('No object.')."
  • \n"; + } + } + $data['success'] = true; } + /** + * Remove related object specify by DN + * + * @param[in] &$data Reference to returned data array + * + * @retval void + */ public static function ajax_deleteByDn(&$data) { - if ((isset($_REQUEST['id'])) && (isset($_REQUEST['dn']))) { - if (isset($_SESSION['LSrelation'][$_REQUEST['id']])) { - $conf = $_SESSION['LSrelation'][$_REQUEST['id']]; - if (LSsession ::loadLSobject($conf['objectType'])) { - $object = new $conf['objectType'](); - if (($object -> loadData($conf['objectDn'])) && (isset($object->config['LSrelation'][$conf['relationName']]))) { - $relation = new LSrelation($object, $conf['relationName']); - if ($relation -> canEdit()) { - $list = $relation -> listRelatedObjects(); - if (is_array($list)) { - $ok=false; - foreach($list as $o) { - if($o -> getDn() == $_REQUEST['dn']) { - if (!$relation -> canEditRelationWithObject($o)) { - LSerror :: addErrorCode('LSsession_11'); - return; - } - if (!$relation -> removeRelationWithObject($o)) { - LSerror :: addErrorCode('LSrelations_03',$conf['relationName']); - } - else { - $ok = true; - } - break; - } - } - if (!$ok) { - LSdebug($_REQUEST['value']." introuvé parmi la liste"); - LSerror :: addErrorCode('LSrelations_03',$conf['relationName']); - } - else { - $data=array( - 'dn' => $_REQUEST['dn'], - 'id' => $_REQUEST['id'] - ); - } - } - else { - LSerror :: addErrorCode('LSrelations_03',$conf['relationName']); - } - } - else { - LSerror :: addErrorCode('LSsession_11'); - } - } - else { - LSerror :: addErrorCode('LSsession_12'); - } + $conf = null; + $object = null; + $relation = null; + if (!self :: _ajax_check_call($data, $conf, $object, $relation, 'dn')) { + return; + } + + // List related objects + $list = $relation -> listRelatedObjects(); + if (!is_array($list)) { + self :: log_warning('Fail to list related objects'); + LSerror :: addErrorCode('LSrelations_03',$conf['relationName']); + return; + } + + // For each related objects: + // - check if DN match + // - check user can edit relation with specific object + // - remove relation + $found = false; + foreach($list as $o) { + if($o -> getDn() == $_REQUEST['dn']) { + if (!$relation -> canEditRelationWithObject($o)) { + LSerror :: addErrorCode('LSsession_11'); + return; + } + if (!$relation -> removeRelationWithObject($o)) { + LSerror :: addErrorCode('LSrelations_03', $conf['relationName']); + return; } else { - LSerror :: addErrorCode('LSsession_12'); + $found = true; } - } - else { - LSerror :: addErrorCode('LSsession_12'); + break; } } + + // Check object found + if (!$found) { + self :: log_warning("Object '".$_REQUEST['dn']."' not found in related objects list."); + LSerror :: addErrorCode('LSrelations_03', $conf['relationName']); + return; + } + + // Set success + $data['dn'] = $_REQUEST['dn']; + $data['success'] = true; } + } /** * Error Codes **/ LSerror :: defineError('LSrelations_01', -_("LSrelation : The function %{function} for action '%{action}' on the relation %{relation} is unknown.") +_("LSrelation : Invalid parameter '%{parameter}' of the relation %{relation}: objects %{LSobject} have no function '%{function}'.") ); LSerror :: defineError('LSrelations_02', _("LSrelation : Relation %{relation} of object type %{LSobject} unknown.") @@ -469,3 +967,9 @@ _("LSrelation : Incomplete configuration for LSrelation %{relation} of object ty LSerror :: defineError('LSrelations_06', _("LSrelation : Invalid editable attribute for LSrelation %{relation} with LSobject %{LSobject}.") ); +LSerror :: defineError('LSrelations_07', +_("LSrelation : The configuration parameter '%{parameter}' of the relation %{relation} of %{LSobject} is missing.") +); +LSerror :: defineError('LSrelations_08', +_("LSrelation : The configuration parameter '%{parameter}' of the relation %{relation} of %{LSobject} is invalid.") +); diff --git a/src/includes/class/class.LSsearchEntry.php b/src/includes/class/class.LSsearchEntry.php index d6a43d6d..a4199cc9 100644 --- a/src/includes/class/class.LSsearchEntry.php +++ b/src/includes/class/class.LSsearchEntry.php @@ -190,14 +190,6 @@ class LSsearchEntry extends LSlog_staticLoggerClass { $this -> LSsearch -> addResultToCache(); return $this -> cache['actions']; } - elseif ($key=='LSselect') { - if (is_array($_SESSION['LSselect'][$this -> LSobject])) { - if(in_array($this -> dn,$_SESSION['LSselect'][$this -> LSobject])) { - return true; - } - } - return; - } elseif (is_array($this->LSsearch->extraDisplayedColumns) && array_key_exists($key,$this->LSsearch->extraDisplayedColumns)) { if(isset($this -> cache[$key])) { return $this -> cache[$key]; diff --git a/src/includes/class/class.LSselect.php b/src/includes/class/class.LSselect.php index 24132154..10fe6883 100644 --- a/src/includes/class/class.LSselect.php +++ b/src/includes/class/class.LSselect.php @@ -20,7 +20,9 @@ ******************************************************************************/ -class LSselect { +LSsession :: loadLSclass('LSlog_staticLoggerClass'); + +class LSselect extends LSlog_staticLoggerClass { /* * Méthode chargeant les dépendances d'affichage @@ -35,47 +37,371 @@ class LSselect { LSsession :: addCssFile('LSselect.css'); } - public static function ajax_addItem(&$data) { - if ((isset($_REQUEST['objecttype'])) && (isset($_REQUEST['objectdn'])) && (isset($_REQUEST['multiple']))) { - if (!$_REQUEST['multiple']) { - $_SESSION['LSselect'][$_REQUEST['objecttype']]=array($_REQUEST['objectdn']); - } - else if (is_array($_SESSION['LSselect'][$_REQUEST['objecttype']])) { - if (!in_array($_REQUEST['objectdn'],$_SESSION['LSselect'][$_REQUEST['objecttype']])) { - $_SESSION['LSselect'][$_REQUEST['objecttype']][]=$_REQUEST['objectdn']; - } + /** + * Init a LSobjects selection + * @param[in] $id string The LSselect ID + * @param[in] $LSobjects array Selectable LSobject types configuration. Must be an array + * with object type as key and configuration as value with the + * following info: + * - object_type: the LSobject type (same as key, required) + * - display_name_format: display name LSformat (optional, default: object type default) + * - filter: LDAP filter string for selectable objects (optional, default: no filter) + * - onlyAccessible: filter on only accessible objects (optional, default: false) + * - editableAttr: attribute name of object that must be writable to the object be selectable (optional) + * @param[in] $multiple boolean True if this selection permit to select more than one object, False otherwise (optional, + * default: false) + * @param[in] $current_selected_objects array|null Array of current selected objects (optional, see setSelectedObjects for format specification) + * @return void + */ + public static function init($id, $LSobjects, $multiple=false, $current_selected_objects=null) { + if ( !isset($_SESSION['LSselect']) || !is_array($_SESSION['LSselect'])) + $_SESSION['LSselect'] = array(); + $_SESSION['LSselect'][$id] = array ( + 'LSobjects' => $LSobjects, + 'multiple' => $multiple, + 'selected_objects' => array(), + ); + if (is_array($current_selected_objects)) + self :: setSelectedObjects($id, $current_selected_objects); + self :: log_debug("Initialized with id=$id: multiple=".($multiple?'yes':'no')." ".count($_SESSION['LSselect'][$id]['selected_objects'])." selected object(s)."); + } + + /** + * Check a LSselect exist by ID + * + * @param[in] $id string The LSselect ID + * + * @retval boolean + */ + public static function exists($id) { + if (isset($_SESSION['LSselect']) && is_array($_SESSION['LSselect']) && + isset($_SESSION['LSselect'][$id]) && is_array($_SESSION['LSselect'][$id])) + return true; + return false; + } + + /** + * Return a configuration parameter (or default value) + * + * @param[] $id string The LSselect ID + * @param[] $param string The configuration parameter + * @param[] $default mixed The default value (optional, default : null) + * @param[] $cast Cast string|null resulting value in specific type (optional, default : null=disabled) + * + * @retval mixed The configuration parameter value or default value if not set + **/ + public static function getConfig($id, $key, $default=null, $cast=null) { + if (!self :: exists($id)) + return false; + return LSconfig :: get($key, $default, $cast, $_SESSION['LSselect'][$id]); + } + + /** + * Check if LSselect exist and is multiple + * + * @param[in] $id string The LSselect ID + * + * @retval boolean + */ + public static function isMultiple($id) { + return self :: getConfig($id, 'multiple', false, 'bool'); + } + + /** + * Get LSsearch object corresponding to the specified selection + * + * @param[in] $id string The LSselect ID + * @param[in] $object_type string|null The object type of the search (optional, + * default: first one object type configured) + * + * @retval LSsearch|false The LSsearch object, or false in case of error + */ + public static function &getSearch($id, $object_type=null) { + // Check parameters + if (!self :: exists($id)) { + self :: log_debug("getSearch($id): does not exists."); + return false; + } + if (is_null($object_type)) + $object_type = array_keys($_SESSION['LSselect'][$id]['LSobjects'])[0]; + elseif (!array_key_exists($object_type, $_SESSION['LSselect'][$id]['LSobjects'])) { + self :: log_debug("getSearch($id): this selection does not joined '$object_type' objects."); + return false; + } + + // Load LSobject type & LSsearch + if ( !LSsession :: loadLSobject($object_type) || !LSsession :: loadLSclass('LSsearch', null, true) ) { + self :: log_debug("getSearch($id): fail to load $object_type object type or LSsearch class"); + return false; + } + + // Instanciate object + $search = new LSsearch($object_type, "LSselect::$id"); + + /* + * Set parameters from config + */ + + // filter (optional) + $filter = self :: getConfig($id, "LSobjects.$object_type.filter"); + if ($filter) $search -> setParam('filter', $filter); + + // display_name_format (optional) + $display_name_format = self :: getConfig($id, "LSobjects.$object_type.display_name_format"); + if ($display_name_format) $search -> setParam('displayFormat', $display_name_format); + + // onlyAccessible (default: false) + $search -> setParam( + 'onlyAccessible', + self :: getConfig($id, "LSobjects.$object_type.onlyAccessible", false, 'bool') + ); + + // Add LSsearchEntry customInfos + $search -> setParam('customInfos', array ( + 'selectable' => array ( + 'function' => array('LSselect', 'selectable'), + 'args' => $id, + ), + 'selected' => array ( + 'function' => array('LSselect', 'selected'), + 'args' => $id, + 'cache' => false, + ), + )); + + return $search; + } + + /** + * Get selectable object types + * + * @param[in] $id string The LSselect ID + * + * @retval array|false Array of selectable object types with name as key + * and label as value, or false if LSselect doesn't exists. + */ + public static function getSelectableObjectTypes($id) { + if (!self :: exists($id)) + return false; + $selectable_objects = array(); + foreach ($_SESSION['LSselect'][$id]['LSobjects'] as $type => $conf) + if (LSsession :: loadLSobject($type)) + $selectable_objects[$type] = LSldapObject :: getLabel($type); + return $selectable_objects; + } + + /** + * Get selectable objects info + * + * @param[in] $id string The LSselect ID + * + * @retval array|false Array of selectable object info with objects's DN as key + * and array of object's info as value. Objects's info returned + * currently contains only the object type (object_type). if + * LSselect specified doesn't exists, this method return false. + */ + public static function getSelectedObjects($id) { + if (!self :: exists($id)) + return false; + if (is_array($_SESSION['LSselect'][$id]['selected_objects'])) + return $_SESSION['LSselect'][$id]['selected_objects']; + return false; + } + + /** + * Set selectable objects info + * + * @param[in] $id string The LSselect ID + * @param[in] $selected_objects array Array of selectable object info with objects's DN + * as key and array of object's info as value. Objects's + * info currently contains only the object type (key=object_type). + * + * @retval array|false Array of selectable object info with objects's DN as key + * and array of object's info as value. Objects's info returned + * currently contains only the object type (object_type). if + * LSselect specified doesn't exists, this method return false. + * + * @retval void + */ + public static function setSelectedObjects($id, $selected_objects) { + if (!self :: exists($id)) + return; + if (!is_array($selected_objects)) + return; + $_SESSION['LSselect'][$id]['selected_objects'] = array(); + foreach($selected_objects as $dn => $info) { + if (!is_array($info) || !isset($info['object_type'])) { + self :: log_warning("setSelectedObjects($id): invalid object info for dn='$dn'"); + continue; } + if (self :: checkObjectIsSelectable($id, $info['object_type'], $dn)) + $_SESSION['LSselect'][$id]['selected_objects'][$dn] = $info; else { - $_SESSION['LSselect'][$_REQUEST['objecttype']][]=$_REQUEST['objectdn']; + self :: log_warning("setSelectedObjects($id): object type='".$info['object_type']."' and dn='$dn' is not selectable".varDump($_SESSION['LSselect'][$id])); } } + self :: log_debug("id=$id: updated with ".count($_SESSION['LSselect'][$id]['selected_objects'])." selected object(s)."); } - public static function ajax_dropItem(&$data) { - if ((isset($_REQUEST['objecttype'])) && (isset($_REQUEST['objectdn']))) { - if (is_array($_SESSION['LSselect'][$_REQUEST['objecttype']])) { - $result=array(); - foreach ($_SESSION['LSselect'][$_REQUEST['objecttype']] as $val) { - if ($val!=$_REQUEST['objectdn']) { - $result[]=$val; - } - } - $_SESSION['LSselect'][$_REQUEST['objecttype']]=$result; + /** + * Check if an object is selectable + * + * @param[in] $id string The LSselect ID + * @param[in] $object_type string The object type + * @param[in] $object_dn string The object DN + * + * @retval boolean True if object is selectable, false otherwise + */ + public static function checkObjectIsSelectable($id, $object_type, $object_dn) { + if (!self :: exists($id)) { + self :: log_warning("checkObjectIsSelectable($id, $object_type, $object_dn): LSselect $id doesn't exists"); + return false; + } + if (!array_key_exists($object_type, $_SESSION['LSselect'][$id]['LSobjects'])) { + self :: log_warning("checkObjectIsSelectable($id, $object_type, $object_dn): object type $object_type not selectabled"); + return false; + } + + // Load LSobject type + if ( !LSsession :: loadLSobject($object_type) ) { + self :: log_warning("checkObjectIsSelectable($id, $object_type, $object_dn): fail to load object type $object_type"); + return false; + } + + // Instanciate object and load object data from DN + $object = new $object_type(); + if (!$object -> loadData($object_dn, self :: getConfig($id, "LSobjects.$object_type.filter", null))) { + self :: log_warning("checkObjectIsSelectable($id, $object_type, $object_dn): object $object_dn not found (or does not match with selection filter)"); + return false; + } + + // Handle onlyAccessible parameter + if (self :: getConfig($id, "LSobjects.$object_type.onlyAccessible", false, 'bool')) { + if (!LSsession :: canAccess($object_type, $object_dn)) { + self :: log_warning("checkObjectIsSelectable($id, $object_type, $object_dn): object $object_dn not accessible"); + return false; } } + + self :: log_debug("checkObjectIsSelectable($id, $object_type, $object_dn): object selectable"); + return true; } - public static function ajax_refreshSession(&$data) { - if ((isset($_REQUEST['objecttype'])) && (isset($_REQUEST['values'])) ) { - $_SESSION['LSselect'][$_REQUEST['objecttype']]=array(); - $values=json_decode($_REQUEST['values'],false); - if (is_array($values)) { - foreach($values as $val) { - $_SESSION['LSselect'][$_REQUEST['objecttype']][]=$val; - } + /* + * AJAX methods + */ + + /** + * Add a selected object to selection + * + * Request parameters: + * - LSselect_id: The LSselect ID + * - object_type: The selected object type + * - object_dn: The selected object DN + * + * Data in answer: + * - success: True if object added to selection, false otherwise + * + * @param[in] &$data Reference to returned data array + * + * @retval void + */ + public static function ajax_addSelectedObject(&$data) { + $data['success'] = false; + if (!isset($_REQUEST['LSselect_id']) || !isset($_REQUEST['object_type']) || !isset($_REQUEST['object_dn'])) { + self :: log_warning('ajax_addSelectedObject(): missing parameter.'); + LSerror :: addErrorCode('LSsession_12'); + return; + } + $id = $_REQUEST['LSselect_id']; + $dn = $_REQUEST['object_dn']; + $type = $_REQUEST['object_type']; + + if (!self :: checkObjectIsSelectable($id, $type, $dn)) { + self :: log_warning("ajax_addSelectedObject($id): object type='$type' dn='$dn' is not selectable."); + return; + } + + self :: log_debug("id=$id: add $type '$dn'"); + if (!$_SESSION['LSselect'][$id]['multiple']) { + $_SESSION['LSselect'][$id]['selected_objects'] = array( + $dn => array('object_type' => $type), + ); + self :: log_debug("ajax_addSelectedObject($id): $dn replace current selected object."); + } + else if (!array_key_exists($dn, $_SESSION['LSselect'][$id]['selected_objects'])) { + $_SESSION['LSselect'][$id]['selected_objects'][$dn] = array('object_type' => $type); + self :: log_debug("ajax_addSelectedObject($id): $dn added to current selected objects."); + } + else { + self :: log_warning("ajax_addSelectedObject($id): $dn already present in selected objects."); + } + $data['success'] = true; + } + + /** + * Drop a selected object in selection + * + * Request parameters: + * - LSselect_id: The LSselect ID + * - object_dn: The selected object DN + * + * Data in answer: + * - success: True if object added to selection, false otherwise + * + * @param[in] &$data Reference to returned data array + * + * @retval void + */ + public static function ajax_dropSelectedObject(&$data) { + $data['success'] = false; + if (!isset($_REQUEST['LSselect_id']) || !isset($_REQUEST['object_dn'])) { + self :: log_warning('ajax_dropSelectedObject(): missing parameter.'); + LSerror :: addErrorCode('LSsession_12'); + return; + } + $id = $_REQUEST['LSselect_id']; + $dn = $_REQUEST['object_dn']; + + if (!self :: exists($id)) { + self :: log_warning("ajax_dropSelectedObject($id): invalid LSselect ID '$id'."); + return; + } + self :: log_debug("id=$id: remove '$dn'"); + if (array_key_exists($dn, $_SESSION['LSselect'][$id]['selected_objects'])) { + unset($_SESSION['LSselect'][$id]['selected_objects'][$dn]); + self :: log_debug("ajax_dropSelectedObject($id): $dn removed from selected objects."); + } + else { + self :: log_warning("ajax_dropSelectedObject($id): $dn not present in selected objects."); + } + $data['success'] = true; + } + + /** + * Update selected objects of the selection + * + * Request parameters: + * - LSselect_id: The LSselect ID + * - selected_objects: Array of selected object info (see setSelectedObjects for format) + * + * Data in answer: any + * + * @param[in] &$data Reference to returned data array + * + * @retval void + */ + public static function ajax_updateSelectedObjects(&$data) { + if (isset($_REQUEST['LSselect_id']) && isset($_REQUEST['selected_objects']) ) { + $selected_objects = json_decode($_REQUEST['selected_objects'], true); + if (is_array($selected_objects)) { + self :: log_debug('ajax_updateSelectedObjects(): set selected objects: '.varDump($selected_objects)); + self :: setSelectedObjects($_REQUEST['LSselect_id'], $selected_objects); } - $data=array( - 'values' => $values + else + self :: log_warning('ajax_updateSelectedObjects(): fail to decode JSON values.'); + $data = array( + 'selected_objects' => $selected_objects ); } else { @@ -83,8 +409,66 @@ class LSselect { } } - public static function selectablly($obj,$args) { - return (LSsession::canEdit($obj->type,$obj->dn,$args))?1:0; + /** + * Get selected objects of the selection + * + * Request parameters: + * - LSselect_id: The LSselect ID + * + * Data in answer: + * - objects: The selected objects info (see getSelectedObjects for format) + * + * @param[in] &$data Reference to returned data array + * + * @retval void + */ + public static function ajax_getSelectedObjects(&$data) { + if (isset($_REQUEST['LSselect_id'])) { + $data=array( + 'objects' => self :: getSelectedObjects($_REQUEST['LSselect_id']) + ); + } + else { + LSerror :: addErrorCode('LSsession_12'); + } + } + + /* + * LSsearchEntry customInfos helpers + */ + + /** + * LSsearchEntry selectable customInfos method : check if object is selectable + * + * @param[in] $obj LSsearchEntry The LSsearchEntry object + * @param[in] $id string The LSselect ID + * + * @retval boolean True if object is selectable, False otherwise + */ + public static function selectable($obj, $id) { + $editableAttr = self :: getConfig($id, "LSobjects.".$obj->type.".editableAttr"); + if (!$editableAttr) + return true; + if ($editableAttr && $obj->type :: hasAttr($editableAttr)) { + return (LSsession::canEdit($obj->type, $obj->dn, $editableAttr))?1:0; + } + return false; + } + + /** + * LSsearchEntry selected customInfos method : check if object is selected + * + * @param[in] $obj LSsearchEntry The LSsearchEntry object + * @param[in] $id string The LSselect ID + * + * @retval boolean True if object is selected, False otherwise + */ + public static function selected($obj, $id) { + if (self :: exists($id) && + is_array($_SESSION['LSselect'][$id]['selected_objects']) && + array_key_exists($obj->dn, $_SESSION['LSselect'][$id]['selected_objects'])) + return true; + return false; } } diff --git a/src/includes/js/LSformElement_select_object_field.js b/src/includes/js/LSformElement_select_object_field.js index e710f394..61a3cff4 100644 --- a/src/includes/js/LSformElement_select_object_field.js +++ b/src/includes/js/LSformElement_select_object_field.js @@ -123,21 +123,23 @@ var LSformElement_select_object_field = new Class({ onAddBtnClick: function(event) { new Event(event).stop(); - values = new Array(); + selected_objects = {}; var inputname=this.name+'[]'; this.ul.getElements('input.LSformElement_select_object').each(function(el) { if (el.name==inputname) { - values.push(el.getProperty('value')); + selected_objects[el.getProperty('value')] = { + 'object_type': el.getProperty('data-object-type'), + }; } }, this); var data = { - objecttype: this.params['object_type'], - values: JSON.encode(values) + LSselect_id: this.params['LSselect_id'], + selected_objects: JSON.encode(selected_objects) }; - data.imgload=varLSdefault.loadingImgDisplay(this.addBtn,'inside'); - new Request({url: 'ajax/class/LSselect/refreshSession', data: data, onSuccess: this.onAddBtnClickComplete.bind(this)}).send(); + data.imgload = varLSdefault.loadingImgDisplay(this.addBtn, 'inside'); + new Request({url: 'ajax/class/LSselect/updateSelectedObjects', data: data, onSuccess: this.onAddBtnClickComplete.bind(this)}).send(); }, onAddBtnClickComplete: function(responseText, responseXML) { @@ -146,17 +148,7 @@ var LSformElement_select_object_field = new Class({ varLSsmoothbox.asNew(); varLSsmoothbox.addEvent('valid',this.onLSsmoothboxValid.bind(this)); varLSsmoothbox.displayValidBtn(); - var url='object/'+this.params['object_type']+'/select'; - var params = []; - if (this.params['multiple']) { - params.push('multiple=1'); - } - if (this.params['filter64']) { - params.push('filter64='+this.params['filter64']); - } - if (params) { - url=url+'?'+params.join('&'); - } + var url='object/select/'+this.params['LSselect_id']; varLSsmoothbox.openURL(url, {width: 635}); } }, @@ -207,7 +199,7 @@ var LSformElement_select_object_field = new Class({ } }, - addLi: function(name,dn) { + addLi: function(info, dn) { if (this.params.multiple) { // Multiple var current = 0; this.ul.getElements("input[type=hidden]").each(function(input){ @@ -224,15 +216,16 @@ var LSformElement_select_object_field = new Class({ var a = new Element('a'); a.addClass('LSformElement_select_object'); - a.href="object/"+this.params['object_type']+"/"+dn; - a.set('html',name); + a.href="object/"+info['object_type']+"/"+dn; + a.set('html', info['name']); a.injectInside(li); var input = new Element('input'); input.setProperties({ - type: 'hidden', - value: dn, - name: this.name+'[]' + 'type': 'hidden', + 'value': dn, + 'name': this.name+'[]', + 'data-object-type': info['object_type'], }); input.addClass('LSformElement_select_object'); input.injectAfter(a); @@ -245,14 +238,15 @@ var LSformElement_select_object_field = new Class({ else { // Non Multiple var a = this.ul.getElement('a'); if ($type(a)) { // Deja initialise - a.href="object/"+this.params['object_type']+"/"+dn; - a.set('html',name); + a.href="object/"+info['object_type']+"/"+dn; + a.set('html',info['name']); a.removeClass('LSformElement_select_object_deleted'); var input = this.ul.getElement('input'); input.setProperties({ - value: dn, - name: this.name+'[]' + 'value': dn, + 'name': this.name+'[]', + 'data-object-type': info['object_type'], }); } else { // Non initialise (No Value) @@ -261,15 +255,16 @@ var LSformElement_select_object_field = new Class({ var a = new Element('a'); a.addClass('LSformElement_select_object'); - a.href="object/"+this.params['object_type']+"/"+dn; - a.set('html',name); + a.href="object/"+info['object_type']+"/"+dn; + a.set('html',info['name']); a.injectInside(li); var input = new Element('input'); input.setProperties({ - type: 'hidden', - value: dn, - name: this.name+'[]' + 'type': 'hidden', + 'value': dn, + 'name': this.name+'[]', + 'data-object-type': info['object_type'], }); input.addClass('LSformElement_select_object'); input.injectAfter(a); @@ -398,7 +393,7 @@ var LSformElement_select_object_field = new Class({ } }, - addSearchAddLi: function(name,dn) { + addSearchAddLi: function(info, dn) { var current = 0; this.ul.getElements("input[type=hidden]").each(function(input){ if ((input.value==dn)&&(input.name == this.name+'[]')) { @@ -409,7 +404,11 @@ var LSformElement_select_object_field = new Class({ var li = new Element('li'); li.addClass('LSformElement_select_object_searchAdd'); li.id = dn; - li.set('html',name); + li.set('html',info['name']); + li.setProperties({ + 'data-dn': dn, + 'data-object-type': info['object_type'], + }); li.addEvent('mouseenter',this.onSearchAddLiMouseEnter.bind(this,li)); li.addEvent('mouseleave',this.onSearchAddLiMouseLeave.bind(this,li)); if (current) { @@ -440,7 +439,13 @@ var LSformElement_select_object_field = new Class({ onSearchAddLiClick: function(li) { this.clearUlIfNoValue(); - this.addLi(li.innerHTML,li.id); + this.addLi( + { + object_type: li.getProperty('data-object-type'), + name: li.innerHTML, + }, + li.getProperty('data-dn') + ); }, closeIfOpenSearchAdd: function(event) { diff --git a/src/includes/js/LSrelation.js b/src/includes/js/LSrelation.js index 35e90b9c..64875867 100644 --- a/src/includes/js/LSrelation.js +++ b/src/includes/js/LSrelation.js @@ -75,7 +75,7 @@ var LSrelation = new Class({ deleteFromImgComplete: function(responseText, responseXML) { var data = JSON.decode(responseText); - if ( varLSdefault.checkAjaxReturn(data) ) { + if ( varLSdefault.checkAjaxReturn(data) && data['success']) { try { var ul=$('LSrelation_ul_'+data.id); var li = $('LSrelation_'+data.id+'_'+data.dn).getParent(); @@ -107,14 +107,14 @@ var LSrelation = new Class({ LSdebug(data); this.refreshRelation=a.id; data.imgload=varLSdefault.loadingImgDisplay('LSrelation_title_'+a.id,'inside'); - new Request({url: 'ajax/class/LSrelation/refreshSession', data: data, onSuccess: this.onLSrelationModifyBtnClickComplete.bind(this)}).send(); + new Request({url: 'ajax/class/LSrelation/initSelection', data: data, onSuccess: this.onLSrelationModifyBtnClickComplete.bind(this)}).send(); }, onLSrelationModifyBtnClickComplete: function(responseText, responseXML) { var data = JSON.decode(responseText); - if ( varLSdefault.checkAjaxReturn(data) ) { + if ( varLSdefault.checkAjaxReturn(data) && data['success'] ) { varLSsmoothbox.asNew(); - varLSsmoothbox.addEvent('valid',this.onLSsmoothboxValid.bind(this)); + varLSsmoothbox.addEvent('valid', this.onLSsmoothboxValid.bind(this)); varLSsmoothbox.openURL(data.href,{startElement: $(data.id), width: 635}); } }, @@ -126,12 +126,12 @@ var LSrelation = new Class({ LSdebug(data); data.imgload=varLSdefault.loadingImgDisplay('LSrelation_title_'+this.refreshRelation,'inside'); - new Request({url: 'ajax/class/LSrelation/refreshList', data: data, onSuccess: this.onLSsmoothboxValidComplete.bind(this)}).send(); + new Request({url: 'ajax/class/LSrelation/updateFromSelection', data: data, onSuccess: this.onLSsmoothboxValidComplete.bind(this)}).send(); }, onLSsmoothboxValidComplete: function(responseText, responseXML) { var data = JSON.decode(responseText); - if ( varLSdefault.checkAjaxReturn(data) ) { + if ( varLSdefault.checkAjaxReturn(data) && data['success'] ) { $('LSrelation_ul_'+this.refreshRelation).set('html',data.html); this.initializeBtn(); } diff --git a/src/includes/js/LSselect.js b/src/includes/js/LSselect.js index ff0752c8..e9a2f7cd 100644 --- a/src/includes/js/LSselect.js +++ b/src/includes/js/LSselect.js @@ -1,17 +1,19 @@ var LSselect = new Class({ initialize: function(){ - this.main_page = $('LSobject-select-main-div').getParent(); this.content = $('content'); - this.multiple = LSselect_multiple; - this.LSselect_search_form = $('LSselect_search_form'); + this.id = this.LSselect_search_form.getElement('input[name=LSselect_id]').value; + this.multiple = this.LSselect_search_form.getElement('input[name=multiple]').value; + + // Add ajax hidden input var input = new Element('input'); input.setProperty('name','ajax'); input.setProperty('type','hidden'); input.injectInside(this.LSselect_search_form); this.tempInput = []; + this.lastCheckboxChanged = null; this.LSselect_search_form.addEvent('submit',this.onSubmitSearchForm.bindWithEvent(this)); @@ -24,6 +26,22 @@ var LSselect = new Class({ this.initializeContent(); varLSdefault.ajaxDisplayDebugAndError(); + + this.title = $('LSselect_title'); + this.tabs_ul = $$('ul.LSselect_selectable_object_types')[0]; + if (this.tabs_ul) { + this.initializeTabs(); + } + }, + + initializeTabs: function(ul) { + this.tabs_ul.getElements('li').addEvent('click', function (event) { + console.log(event.target); + this.LSselect_search_form.getElement('input[name=LSobject]').value = event.target.getProperty('data-object-type'); + this.tabs_ul.getElements('li.current').each(function(li){ console.log(li); li.removeClass('current'); }); + event.target.addClass('current'); + this.submitSearchForm(); + }.bind(this)); }, initializeContent: function() { @@ -48,30 +66,48 @@ var LSselect = new Class({ }, this); }, + loadingImgDisplay: function(place, position) { + if (!place) { + if (this.title) { + place = this.title; + } + else if (this.tabs_ul) { + place = this.tabs_ul; + } + } + if (!position) { + position = 'inside'; + } + return varLSdefault.loadingImgDisplay(place, position); + }, + oncheckboxChange: function(checkbox){ + this.lastCheckboxChanged = checkbox; + var url; if (checkbox.checked) { - var url = 'ajax/class/LSselect/addItem'; - var data = { - objectdn: checkbox.value, - objecttype: $('LSselect-object').getProperties('caption').caption, - multiple: this.multiple - }; + url = 'ajax/class/LSselect/addSelectedObject'; } else { - var url = 'ajax/class/LSselect/dropItem'; - var data = { - objectdn: checkbox.value, - objecttype: $('LSselect-object').getProperties('caption').caption, - multiple: this.multiple - }; + url = 'ajax/class/LSselect/dropSelectedObject'; } - data.imgload=varLSdefault.loadingImgDisplay(checkbox.getParent().getNext(),'inside'); + var data = { + LSselect_id: this.id, + object_dn: checkbox.value, + object_type: $('LSselect-object').getProperties('caption').caption, + }; + data.imgload = this.loadingImgDisplay(checkbox.getParent().getNext(), 'inside'); new Request({url: url, data: data, onSuccess: this.oncheckboxChangeComplete.bind(this)}).send(); }, oncheckboxChangeComplete: function(responseText, responseXML) { var data = JSON.decode(responseText); - varLSdefault.loadingImgHide(data.imgload); + var success = false; + if(varLSdefault.checkAjaxReturn(data)) { + success = data.success; + } + if (!success && this.lastCheckboxChanged) { + this.lastCheckboxChanged.checked = !this.lastCheckboxChanged.checked; + } }, onChangePageClick: function(event, a) { @@ -79,7 +115,7 @@ var LSselect = new Class({ var data = { ajax: true }; - this.searchImgload = varLSdefault.loadingImgDisplay($('LSselect_title'),'inside'); + this.searchImgload = this.loadingImgDisplay(); new Request({url: a.href, data: data, onSuccess: this.onChangePageClickComplete.bind(this)}).send(); }, @@ -98,8 +134,8 @@ var LSselect = new Class({ this.submitSearchForm(); }, - submitSearchForm: function() { - this.searchImgload = varLSdefault.loadingImgDisplay($('LSselect_title'),'inside'); + submitSearchForm: function(loading_img_place) { + this.searchImgload = this.loadingImgDisplay(); this.LSselect_search_form.set('send',{ data: this.LSselect_search_form, evalScripts: true, diff --git a/src/includes/routes.php b/src/includes/routes.php index bc2182b3..80512897 100644 --- a/src/includes/routes.php +++ b/src/includes/routes.php @@ -605,46 +605,32 @@ LSurl :: add_handler('#^custom_search_action\.php#', 'handle_old_custom_search_a * @retval void **/ function handle_LSobject_select($request) { - $object = get_LSobject_from_request($request, true); - if (!$object) - return; - - $LSobject = $object -> getType(); - - if (!LSsession :: loadLSclass('LSsearch')) { + if (!LSsession :: loadLSclass('LSselect')) { LSsession :: addErrorCode('LSsession_05', 'LSsearch'); LSsession :: displayTemplate(); return false; } + if (!LSselect :: exists($request->LSselect_id)) { + LSurl :: error_404($request); + return; + } + // Instanciate LSsearch - $LSsearch = new LSsearch($LSobject,'LSselect'); + $LSsearch = LSselect :: getSearch( + $request->LSselect_id, + (isset($_REQUEST['LSobject'])?$_REQUEST['LSobject']:null) + ); + if (!$LSsearch) + LSlog :: fatal('Fail to retreive search from context.'); + + $LSobject = $LSsearch -> LSobject; + $object = new $LSobject(); + + // Handle form POST data $LSsearch -> setParamsFormPostData(); - $LSsearch -> setParam('nbObjectsByPage', NB_LSOBJECT_LIST_SELECT); + $LSsearch -> setParam('nbObjectsByPage', 4); - // Handle parameters - $selectablly = (isset($_REQUEST['selectablly'])?$_REQUEST['selectablly']:0); - - if (is_string($_REQUEST['editableAttr'])) { - $LSsearch -> setParam( - 'customInfos', - array ( - 'selectablly' => array ( - 'function' => array('LSselect', 'selectablly'), - 'args' => $_REQUEST['editableAttr'] - ) - ) - ); - $selectablly=1; - } - - if (!empty($_REQUEST['filter64'])) { - $filter = base64_decode($_REQUEST['filter64'], 1); - if ($filter) { - $LSsearch -> setParam('filter', $filter); - } - } - $multiple = (isset($_REQUEST['multiple'])?1:0); $page = (isset($_REQUEST['page'])?(int)$_REQUEST['page']:0); // Run search @@ -656,23 +642,16 @@ function handle_LSobject_select($request) { array( array ( 'label' => 'Refresh', - 'url' => "object/$LSobject/select?refresh", + 'url' => "object/select/".$request->LSselect_id."?refresh", 'action' => 'refresh' ) ) ); LStemplate :: assign('searchForm', array ( - 'action' => "object/$LSobject/select", + 'action' => "object/select/".$request->LSselect_id, 'recursive' => (! LSsession :: isSubDnLSobject($LSobject) && LSsession :: subDnIsEnabled() ), - 'multiple' => $multiple, - 'selectablly' => $selectablly, - 'labels' => array ( - 'submit' => _('Search'), - 'approx' => _('Approximative search'), - 'recursive' => _('Recursive search'), - 'level' => _('Level') - ), + 'multiple' => LSselect :: isMultiple($request->LSselect_id), 'values' => array ( 'pattern' => $LSsearch->getParam('pattern'), 'approx' => $LSsearch->getParam('approx'), @@ -685,16 +664,17 @@ function handle_LSobject_select($request) { 'hiddenFields' => array_merge( $LSsearch -> getHiddenFieldForm(), array( - 'ajax' => 1, - 'filter64' => $_REQUEST['filter64'], - 'selectablly' => $selectablly, - 'multiple' => $multiple + 'LSselect_id' => $request->LSselect_id, + 'multiple' => LSselect :: isMultiple($request->LSselect_id), ) ) ) ); LStemplate :: assign('page', $LSsearch -> getPage($page)); LStemplate :: assign('LSsearch', $LSsearch); + LStemplate :: assign('LSselect_id', $request->LSselect_id); + LStemplate :: assign('selectable_object_types', LSselect :: getSelectableObjectTypes($request->LSselect_id)); + LStemplate :: assign('selectable_object_type', $LSobject); LStemplate :: assign('LSobject_list_objectname', $object -> getLabel()); // Set & display template @@ -703,7 +683,7 @@ function handle_LSobject_select($request) { LSsession :: displayTemplate(); $LSsearch->afterUsingResult(); } -LSurl :: add_handler('#^object/(?P[^/]+)/select?$#', 'handle_LSobject_select'); +LSurl :: add_handler('#^object/select/(?P[^/]+)/?$#', 'handle_LSobject_select'); /* * Handle old select.php request for retro-compatibility @@ -716,14 +696,7 @@ function handle_old_select_php($request) { if (!isset($_GET['LSobject'])) $url = null; else { - $url = "object/".$_GET['LSobject']."/select"; - // Preserve GET parameters - $params = array(); - foreach (array('filter64', 'multiple', 'selectablly', 'editableAttr', 'page', 'ajax', 'refresh') as $param) - if (isset($_GET[$param])) - $params[] = $param.'='.$_GET[$param]; - if ($params) - $url .= '?'.implode('&', $params); + $url = "object/".$_GET['LSobject']; } LSerror :: addErrorCode('LSsession_26', 'select.php'); LSurl :: redirect($url); @@ -818,9 +791,9 @@ function handle_LSobject_create($request) { if (LSsession :: loadLSobject($_GET['relatedLSobject']) && LSsession :: loadLSclass('LSrelation')) { $obj = new $_GET['relatedLSobject'](); if ($obj -> loadData(urldecode($_GET['relatedLSobjectDN']))) { - $relation = new LSrelation($obj, $_GET['LSrelation']); - if ($relation -> exists()) { - $attr = $relation -> getRelatedEditableAttribute(); + if (LSrelation :: exists($_GET['relatedLSobject'], $_GET['LSrelation'])) { + $relation = new LSrelation($obj, $_GET['LSrelation']); + $attr = $relation -> relatedEditableAttribute; if (isset($object -> attrs[$attr])) { $value = $relation -> getRelatedKeyValue(); if (is_array($value)) $value=$value[0]; @@ -830,6 +803,9 @@ function handle_LSobject_create($request) { LSerror :: addErrorCode('LSrelations_06',array('relation' => $relation -> getName(),'LSobject' => $obj -> getType())); } } + else { + LSlog :: warning("Relation '".$_GET['LSrelation']."' of object type '".$_GET['relatedLSobject']."' does not exists."); + } } else { LSerror :: addErrorCode('LSsession_24'); diff --git a/src/templates/default/LSformElement_select_object.tpl b/src/templates/default/LSformElement_select_object.tpl index 59f922f7..836d80af 100644 --- a/src/templates/default/LSformElement_select_object.tpl +++ b/src/templates/default/LSformElement_select_object.tpl @@ -4,11 +4,11 @@ {/if}
      - {foreach from=$values item=txt key=dn} + {foreach from=$values item=info key=dn}
    • {include file="ls:$fieldTemplate"}
    • {foreachelse} - {assign var=dn value=""} - {assign var=txt value=""} + {assign var=dn value=""} + {assign var=info value=array()}
    • {include file="ls:$fieldTemplate"}
    • {/foreach}
    diff --git a/src/templates/default/LSformElement_select_object_field.tpl b/src/templates/default/LSformElement_select_object_field.tpl index 742843c6..1b2551b8 100644 --- a/src/templates/default/LSformElement_select_object_field.tpl +++ b/src/templates/default/LSformElement_select_object_field.tpl @@ -1,6 +1,6 @@ {if $dn} - {$txt|escape:"htmlall"} - {if !$freeze}{/if} + {$info.name|escape:"htmlall"} + {if !$freeze}{/if} {else} {$noValueTxt|escape:"htmlall"} {/if} diff --git a/src/templates/default/select.tpl b/src/templates/default/select.tpl index 36c1c0ff..0e291947 100644 --- a/src/templates/default/select.tpl +++ b/src/templates/default/select.tpl @@ -1,15 +1,23 @@
    + {if count($selectable_object_types) == 1}

    {$pagetitle|escape:"htmlall"}

    + {else} +
      + {foreach $selectable_object_types as $type => $label} +
    • {$label}
    • + {/foreach} +
    + {/if}
    diff --git a/src/templates/default/select_table.tpl b/src/templates/default/select_table.tpl index 3dd4b4a2..eb133e39 100644 --- a/src/templates/default/select_table.tpl +++ b/src/templates/default/select_table.tpl @@ -26,7 +26,11 @@ {foreach from=$page.list item=object} - LSselect}checked="true"{/if}{if $searchForm.selectablly}{if !$object->selectablly} disabled="disabled"{/if}{/if} class='LSobject-select' /> + + selected}checked="true"{/if} + {if !$object->selectable}disabled="disabled"{/if} class='LSobject-select' /> + {$object->displayName|escape:"htmlall"} {if $LSsearch->displaySubDn} {$object->subDn|escape:"htmlall"} @@ -52,21 +56,21 @@ {else} {assign var=start value=0} {/if} - < + < {foreach from=0|range:10 item=i} {if $page.nb==$start+$i} {$page.nb+1} {else} - {$i+$start+1} + {$i+$start+1} {/if} {/foreach} - > + > {else} {section name=listpage loop=$page.nbPages step=1} {if $page.nb == $smarty.section.listpage.index} {$page.nb+1} {else} - {$smarty.section.listpage.index+1} + {$smarty.section.listpage.index+1} {/if} {/section} {/if}