Correct how we derive attributes. This is not completed yet and does not catch all...
authorGunnar Wrobel <p@rdus.de>
Mon, 6 Apr 2009 09:44:39 +0000 (11:44 +0200)
committerGunnar Wrobel <p@rdus.de>
Mon, 6 Apr 2009 10:26:00 +0000 (12:26 +0200)
framework/Kolab_Server/lib/Horde/Kolab/Server/Object.php
framework/Kolab_Server/lib/Horde/Kolab/Server/Object/Person.php

index e9af973..3bef639 100644 (file)
@@ -72,6 +72,14 @@ class Horde_Kolab_Server_Object
     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
@@ -335,31 +343,104 @@ class Horde_Kolab_Server_Object
      *
      * @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.
@@ -417,7 +498,9 @@ class Horde_Kolab_Server_Object
      *
      * @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)
     {
@@ -430,6 +513,19 @@ class Horde_Kolab_Server_Object
             }
         }
 
+        $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])) {
@@ -488,12 +584,6 @@ class Horde_Kolab_Server_Object
             }
         }
 
-        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;
index 3656106..2044404 100644 (file)
@@ -30,6 +30,7 @@ class Horde_Kolab_Server_Object_Person extends Horde_Kolab_Server_Object
 
     const ATTRIBUTE_CN           = 'cn';
     const ATTRIBUTE_SN           = 'sn';
+    const ATTRIBUTE_SNSUFFIX     = 'snsuffix';
     const ATTRIBUTE_USERPASSWORD = 'userPassword';
 
     const OBJECTCLASS_PERSON     = 'person';
@@ -45,6 +46,16 @@ class Horde_Kolab_Server_Object_Person extends Horde_Kolab_Server_Object
             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,
@@ -55,51 +66,40 @@ class Horde_Kolab_Server_Object_Person extends Horde_Kolab_Server_Object
     );
 
     /**
-     * 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