private $_cache = false;
/**
+ * Cache for derived values. This may not be the same cache as the original
+ * value cache as some attributes may have the same name.
+ *
+ * @var array
+ */
+ private $_derivative_cache = array();
+
+ /**
* Does the object exist in the LDAP database?
*
* @var boolean
*
* @return mixed The value of the attribute.
*/
- protected function derive($attr)
+ protected function derive($attr, $separator = '$')
{
switch ($attr) {
case self::ATTRIBUTE_ID:
return substr($this->uid, 0,
strlen($this->uid) - strlen($this->server->getBaseUid()) - 1);
+ default:
+ $basekey = $this->attributes[$attr]['base'];
+ $base = $this->_get($basekey);
+ if (empty($base)) {
+ return;
+ }
+ $fields = explode($separator, $base);
+ //FIXME: Fill the cache here
+ return isset($fields[$this->attributes[$attr]['order']]) ? $fields[$this->attributes[$attr]['order']] : null;
+
}
}
/**
* Collapse derived values back into the main attributes.
*
- * @param string $attr The attribute to collapse.
- * @param array $info The information currently working on.
+ * @param string $key The attribute to collapse into.
+ * @param array $attributes The attribute to collapse.
+ * @param array $info The information currently working on.
+ * @param string $separator Separate the fields using this character.
*
- * @return mixed The value of the attribute.
+ * @return NULL.
*/
- protected function collapse($attr, &$info)
+ protected function collapse($key, $attributes, &$info, $separator = '$')
{
switch ($attr) {
default:
+ /**
+ * Check how many empty entries we have at the end of the array. We
+ * may omit these together with their field separators.
+ */
+ krsort($attributes);
+ $empty = count($attributes);
+ foreach ($attributes as $attribute) {
+ if (empty($info[$attribute])) {
+ $empty--;
+ } else {
+ break;
+ }
+ }
+ ksort($attributes);
+ $unset = $attributes;
+ $result = '';
+ for ($i = 0; $i < $empty; $i++) {
+ $akey = array_shift($attributes);
+ //FIXME: We don't handle multiple values correctly here
+ $value = isset($info[$akey]) ? $info[$akey] : '';
+ if (is_array($value)) {
+ $value = $value[0];
+ }
+ $result .= $this->quote($value);
+ if ($i != ($empty - 1)) {
+ $result .= $separator;
+ }
+ }
+ foreach ($unset as $attribute) {
+ unset($info[$attribute]);
+ }
+
+ $info[$key] = $result;
}
}
/**
+ * Quote field separaotrs within a LDAP value.
+ *
+ * @param string $string The string that should be quoted.
+ *
+ * @return string The quoted string.
+ */
+ protected function quote($string)
+ {
+ return str_replace(array('\\', '$',),
+ array('\\5c', '\\24',),
+ $string);
+ }
+
+ /**
+ * Unquote a LDAP value.
+ *
+ * @param string $string The string that should be unquoted.
+ *
+ * @return string The unquoted string.
+ */
+ protected function unquote($string)
+ {
+ return str_replace(array('\\5c', '\\24',),
+ array('\\', '$',),
+ $string);
+ }
+
+ /**
* Convert the object attributes to a hash.
*
* @param string $attrs The attributes to return.
*
* @param array $info The information about the object.
*
- * @return boolean|PEAR_Error True on success.
+ * @return boolean True on success.
+ *
+ * @throws Horde_Kolab_Server_Exception If saving the data failed.
*/
public function save($info)
{
}
}
+ $collapse = array();
+ foreach ($this->attribute_map['derived'] as $key) {
+ $attribute = $this->attributes[$key];
+ if (isset($attribute['base'])
+ && isset($attribute['order'])) {
+ $collapse[$attribute['base']][$attribute['order']] = $key;
+ }
+ }
+
+ foreach ($collapse as $key => $attributes) {
+ $this->collapse($key, $attributes, $info);
+ }
+
if (!$this->exists()) {
foreach ($this->attribute_map['required'] as $key) {
if (!in_array($key, array_keys($info)) || empty($info[$key])) {
}
}
- foreach ($this->attribute_map['derived'] as $attribute) {
- if (isset($info[$attribute])) {
- $this->collapse($attribute, $info);
- }
- }
-
$result = $this->server->save($this->uid, $info, $this->exists());
$this->_exists = true;
const ATTRIBUTE_CN = 'cn';
const ATTRIBUTE_SN = 'sn';
+ const ATTRIBUTE_SNSUFFIX = 'snsuffix';
const ATTRIBUTE_USERPASSWORD = 'userPassword';
const OBJECTCLASS_PERSON = 'person';
self::ATTRIBUTE_SN,
self::ATTRIBUTE_USERPASSWORD,
),
+ 'derived' => array(
+ self::ATTRIBUTE_SN => array(
+ 'base' => self::ATTRIBUTE_SN,
+ 'order' => 0,
+ ),
+ self::ATTRIBUTE_SNSUFFIX => array(
+ 'base' => self::ATTRIBUTE_SN,
+ 'order' => 1,
+ ),
+ ),
'required' => array(
self::ATTRIBUTE_CN,
self::ATTRIBUTE_SN,
);
/**
- * Derive an attribute value.
+ * Generates an ID for the given information.
*
- * @param string $attr The attribute to derive.
+ * @param array $info The data of the object.
*
- * @return mixed The value of the attribute.
+ * @static
+ *
+ * @return string The ID.
*/
- protected function derive($attr)
+ public static function generateId($info)
{
- switch ($attr) {
- case self::ATTRIBUTE_ID:
- $result = split(',', $this->uid);
- if (substr($result[0], 0, 3) == 'cn=') {
- return substr($result[0], 3);
- } else {
- return $result[0];
- }
- default:
- return parent::derive($attr);
+ if (!empty($info[self::ATTRIBUTE_CN])) {
+ return self::ATTRIBUTE_CN . '=' . $info[self::ATTRIBUTE_CN];
}
+ return self::ATTRIBUTE_CN . '=' . $info[self::ATTRIBUTE_SN];
}
/**
- * Generates an ID for the given information.
+ * Saves object information. This may either create a new entry or modify an
+ * existing entry.
*
- * @param array $info The data of the object.
+ * Please note that fields with multiple allowed values require the callee
+ * to provide the full set of values for the field. Any old values that are
+ * not resubmitted will be considered to be deleted.
*
- * @static
+ * @param array $info The information about the object.
*
- * @return string|PEAR_Error The ID.
+ * @return boolean|PEAR_Error True on success.
*/
- public static function generateId($info)
+ public function save($info)
{
- $id_mapfields = array('givenName', 'sn');
- $id_format = '%s %s';
-
- $fieldarray = array();
- foreach ($id_mapfields as $mapfield) {
- if (isset($info[$mapfield])) {
- $fieldarray[] = $info[$mapfield];
- } else {
- $fieldarray[] = '';
- }
+ if (empty($info[self::ATTRIBUTE_CN])
+ && !empty($info[self::ATTRIBUTE_SN])) {
+ $info[self::ATTRIBUTE_CN] = $info[self::ATTRIBUTE_SN];
}
-
- return trim(vsprintf($id_format, $fieldarray), " \t\n\r\0\x0B,");
+ return parent::save($info);
}
-
}
\ No newline at end of file