Branch 'dev/kolab3' - plugins/kolab_addressbook plugins/libkolab

Thomas Brüderli bruederli at kolabsys.com
Wed May 16 10:11:13 CEST 2012


 plugins/kolab_addressbook/lib/rcube_kolab_contacts.php |   55 ++++++++++-------
 plugins/libkolab/SQL/mysql.sql                         |    2 
 plugins/libkolab/lib/kolab_format_contact.php          |    2 
 plugins/libkolab/lib/kolab_storage_cache.php           |   22 +++---
 4 files changed, 49 insertions(+), 32 deletions(-)

New commits:
commit 4b5c2ce98551c8dbff40e679793c6901466132dc
Author: Thomas Bruederli <thomas at roundcube.net>
Date:   Wed May 16 10:10:51 2012 +0200

    Add some fulltext searching capabilities to kolab_storage_cache and use them for search (autocompletion) in Kolab address books

diff --git a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
index 37ba1f1..5b7fd8d 100644
--- a/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
+++ b/plugins/kolab_addressbook/lib/rcube_kolab_contacts.php
@@ -314,8 +314,6 @@ class rcube_kolab_contacts extends rcube_addressbook
      */
     public function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array())
     {
-        $this->_fetch_contacts();
-
         // search by ID
         if ($fields == $this->primary_key) {
             $ids    = !is_array($value) ? explode(',', $value) : $value;
@@ -350,6 +348,25 @@ class rcube_kolab_contacts extends rcube_addressbook
         // build key name regexp
         $regexp = '/^(' . implode($fields, '|') . ')(?:.*)$/';
 
+        // pass query to storage if only indexed cols are involved
+        // NOTE: this is only some rough pre-filtering but probably includes false positives
+        $squery = array();
+        if (count(array_intersect(kolab_format_contact::$fulltext_cols, $fields)) == $scount) {
+            switch ($mode) {
+                case 1:  $prefix = ' '; $suffix = ' '; break;  // strict
+                case 2:  $prefix = ' '; $suffix = '';  break;  // prefix
+                default: $prefix = '';  $suffix = '';  break;  // substring
+            }
+
+            $search_string = is_array($value) ? join(' ', $value) : $value;
+            foreach (rcube_utils::normalize_string($search_string, true) as $word) {
+                $squery[] = array('words', 'LIKE', '%' . $prefix . $word . $suffix . '%');
+            }
+        }
+
+        // get all/matching records
+        $this->_fetch_contacts($squery);
+
         // save searching conditions
         $this->filter = array('fields' => $fields, 'value' => $value, 'mode' => $mode, 'ids' => array());
 
@@ -374,17 +391,19 @@ class rcube_kolab_contacts extends rcube_addressbook
                 }
 
                 foreach ((array)$contact[$col] as $val) {
-                    $val = mb_strtolower($val);
-                    switch ($mode) {
-                    case 1:
-                        $got = ($val == $search);
-                        break;
-                    case 2:
-                        $got = ($search == substr($val, 0, strlen($search)));
-                        break;
-                    default:
-                        $got = (strpos($val, $search) !== false);
-                        break;
+                    foreach ((array)$val as $str) {
+                        $str = mb_strtolower($str);
+                        switch ($mode) {
+                        case 1:
+                            $got = ($str == $search);
+                            break;
+                        case 2:
+                            $got = ($search == substr($str, 0, strlen($search)));
+                            break;
+                        default:
+                            $got = (strpos($str, $search) !== false);
+                            break;
+                        }
                     }
 
                     if ($got) {
@@ -916,17 +935,13 @@ class rcube_kolab_contacts extends rcube_addressbook
     }
 
     /**
-     * Simply fetch all records and store them in private member vars
+     * Query storage layer and store records in private member var
      */
-    private function _fetch_contacts()
+    private function _fetch_contacts($query = array())
     {
         if (!isset($this->contacts)) {
             $this->contacts = array();
-            foreach ((array)$this->storagefolder->get_objects() as $record) {
-                // Because of a bug, sometimes group records are returned
-                if ($record['__type'] == 'Group')
-                    continue;
-
+            foreach ((array)$this->storagefolder->select($query) as $record) {
                 $contact = $this->_to_rcube_contact($record);
                 $id = $contact['ID'];
                 $this->contacts[$id] = $contact;
diff --git a/plugins/libkolab/SQL/mysql.sql b/plugins/libkolab/SQL/mysql.sql
index 5f49e92..55d0dbc 100644
--- a/plugins/libkolab/SQL/mysql.sql
+++ b/plugins/libkolab/SQL/mysql.sql
@@ -11,10 +11,12 @@ CREATE TABLE IF NOT EXISTS `kolab_cache` (
   `type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
   `msguid` BIGINT UNSIGNED NOT NULL,
   `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL,
+  `created` DATETIME DEFAULT NULL,
   `data` TEXT NOT NULL,
   `xml` TEXT NOT NULL,
   `dtstart` DATETIME,
   `dtend` DATETIME,
   `tags` VARCHAR(255) NOT NULL,
+  `words` TEXT NOT NULL,
   PRIMARY KEY(`resource`,`type`,`msguid`)
 ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
diff --git a/plugins/libkolab/lib/kolab_format_contact.php b/plugins/libkolab/lib/kolab_format_contact.php
index 646f6ca..1f20e3e 100644
--- a/plugins/libkolab/lib/kolab_format_contact.php
+++ b/plugins/libkolab/lib/kolab_format_contact.php
@@ -427,7 +427,7 @@ class kolab_format_contact extends kolab_format
     {
         $data = '';
         foreach (self::$fulltext_cols as $col) {
-            $val = is_array($this->data[$col]) ? join(" ", $this->data[$col]) : $this->data[$col];
+            $val = is_array($this->data[$col]) ? join(' ', $this->data[$col]) : $this->data[$col];
             if (strlen($val))
                 $data .= $val . ' ';
         }
diff --git a/plugins/libkolab/lib/kolab_storage_cache.php b/plugins/libkolab/lib/kolab_storage_cache.php
index 72373e1..7978411 100644
--- a/plugins/libkolab/lib/kolab_storage_cache.php
+++ b/plugins/libkolab/lib/kolab_storage_cache.php
@@ -364,7 +364,7 @@ class kolab_storage_cache
     {
         $sql_where = '';
         foreach ($query as $param) {
-            $sql_where .= sprintf(' AND %s%s%s',
+            $sql_where .= sprintf(' AND %s %s %s',
                 $this->db->quote_identifier($param[0]),
                 $param[1],
                 $this->db->quote($param[2])
@@ -431,8 +431,8 @@ class kolab_storage_cache
 
         if ($object['_formatobj']) {
             $sql_data['xml'] = (string)$object['_formatobj']->write();
-            $sql_data['tags'] = join(' ', $object['_formatobj']->get_tags());
-            $sql_data['words'] = join(' ', $object['_formatobj']->get_words());
+            $sql_data['tags'] = ' ' . join(' ', $object['_formatobj']->get_tags()) . ' ';  // pad with spaces for strict/prefix search
+            $sql_data['words'] = ' ' . join(' ', $object['_formatobj']->get_words()) . ' ';
         }
 
         // extract object data
@@ -492,7 +492,7 @@ class kolab_storage_cache
             return false;
 
         $sql_arr = $this->db->fetch_assoc($this->db->query(
-            "SELECT msguid AS locked FROM kolab_cache ".
+            "SELECT msguid AS locked, ".$this->db->unixtimestamp('created')." AS created FROM kolab_cache ".
             "WHERE resource=? AND type=?",
             $this->resource_uri,
             'lock'
@@ -501,24 +501,24 @@ class kolab_storage_cache
         // create lock record if not exists
         if (!$sql_arr) {
             $this->db->query(
-                "INSERT INTO kolab_cache (resource, type, msguid, uid, data, xml)".
-                " VALUES (?, ?, ?, '', '', '')",
+                "INSERT INTO kolab_cache (resource, type, msguid, created, uid, data, xml)".
+                " VALUES (?, ?, 1, ?, '', '', '')",
                 $this->resource_uri,
                 'lock',
-                time()
+                date('Y-m-d H:i:s')
             );
         }
         // wait if locked (expire locks after 10 minutes)
-        else if (intval($sql_arr['locked']) > 0 && (time() - $sql_arr['locked']) < 600) {
+        else if (intval($sql_arr['locked']) > 0 && (time() - $sql_arr['created']) < 600) {
             usleep(500000);
             return $this->_sync_lock();
         }
         // set lock
         else {
             $this->db->query(
-                "UPDATE kolab_cache SET msguid=? ".
+                "UPDATE kolab_cache SET msguid=1, created=? ".
                 "WHERE resource=? AND type=?",
-                time(),
+                date('Y-m-d H:i:s'),
                 $this->resource_uri,
                 'lock'
             );
@@ -533,7 +533,7 @@ class kolab_storage_cache
     private function _sync_unlock()
     {
         $this->db->query(
-            "UPDATE kolab_cache SET msguid=0 ".
+            "UPDATE kolab_cache SET msguid=0, created='' ".
             "WHERE resource=? AND type=?",
             $this->resource_uri,
             'lock'





More information about the commits mailing list