Changeset 3d6c04d in github


Ignore:
Timestamp:
Apr 22, 2010 7:23:21 AM (3 years ago)
Author:
alecpl <alec@…>
Branches:
master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.6, release-0.7, release-0.8
Children:
3e696da
Parents:
5318bac
Message:
  • SQL performance fixes + code formatting
File:
1 edited

Legend:

Unmodified
Added
Removed
  • program/include/rcube_contacts.php

    rc69d2ae r3d6c04d  
    66 |                                                                       | 
    77 | This file is part of the RoundCube Webmail client                     | 
    8  | Copyright (C) 2006-2009, RoundCube Dev. - Switzerland                 | 
     8 | Copyright (C) 2006-2010, RoundCube Dev. - Switzerland                 | 
    99 | Licensed under the GNU GPL                                            | 
    1010 |                                                                       | 
     
    2828class rcube_contacts extends rcube_addressbook 
    2929{ 
    30   var $db = null; 
    31   var $db_name = ''; 
    32   var $user_id = 0; 
    33   var $filter = null; 
    34   var $result = null; 
    35   var $search_fields; 
    36   var $search_string; 
    37   var $table_cols = array('name', 'email', 'firstname', 'surname', 'vcard'); 
     30    private $db = null; 
     31    private $db_name = ''; 
     32    private $user_id = 0; 
     33    private $filter = null; 
     34    private $result = null; 
     35    private $search_fields; 
     36    private $search_string; 
     37    private $table_cols = array('name', 'email', 'firstname', 'surname', 'vcard'); 
    3838   
    39   /** public properties */ 
    40   var $primary_key = 'contact_id'; 
    41   var $readonly = false; 
    42   var $groups = true; 
    43   var $list_page = 1; 
    44   var $page_size = 10; 
    45   var $group_id = 0; 
    46   var $ready = false; 
     39    /** public properties */ 
     40    var $primary_key = 'contact_id'; 
     41    var $readonly = false; 
     42    var $groups = true; 
     43    var $list_page = 1; 
     44    var $page_size = 10; 
     45    var $group_id = 0; 
     46    var $ready = false; 
    4747 
    4848   
    49   /** 
    50    * Object constructor 
    51    * 
    52    * @param object  Instance of the rcube_db class 
    53    * @param integer User-ID 
    54    */ 
    55   function __construct($dbconn, $user) 
    56   { 
    57     $this->db = $dbconn; 
    58     $this->db_name = get_table_name('contacts'); 
    59     $this->user_id = $user; 
    60     $this->ready = $this->db && !$this->db->is_error(); 
    61   } 
    62  
    63  
    64   /** 
    65    * Save a search string for future listings 
    66    * 
    67    * @param  string SQL params to use in listing method 
    68    */ 
    69   function set_search_set($filter) 
    70   { 
    71     $this->filter = $filter; 
    72   } 
     49    /** 
     50     * Object constructor 
     51     * 
     52     * @param object  Instance of the rcube_db class 
     53     * @param integer User-ID 
     54     */ 
     55    function __construct($dbconn, $user) 
     56    { 
     57        $this->db = $dbconn; 
     58        $this->db_name = get_table_name('contacts'); 
     59        $this->user_id = $user; 
     60        $this->ready = $this->db && !$this->db->is_error(); 
     61    } 
     62 
     63 
     64    /** 
     65     * Save a search string for future listings 
     66     * 
     67     * @param  string SQL params to use in listing method 
     68     */ 
     69    function set_search_set($filter) 
     70    { 
     71        $this->filter = $filter; 
     72    } 
     73 
     74   
     75    /** 
     76     * Getter for saved search properties 
     77     * 
     78     * @return mixed Search properties used by this class 
     79     */ 
     80    function get_search_set() 
     81    { 
     82        return $this->filter; 
     83    } 
     84 
     85 
     86    /** 
     87     * Setter for the current group 
     88     * (empty, has to be re-implemented by extending class) 
     89     */ 
     90    function set_group($gid) 
     91    { 
     92        $this->group_id = $gid; 
     93    } 
     94 
     95 
     96    /** 
     97     * Reset all saved results and search parameters 
     98     */ 
     99    function reset() 
     100    { 
     101        $this->result = null; 
     102        $this->filter = null; 
     103        $this->search_fields = null; 
     104        $this->search_string = null; 
     105    } 
     106   
     107 
     108    /** 
     109     * List all active contact groups of this source 
     110     * 
     111     * @param string  Search string to match group name 
     112     * @return array  Indexed list of contact groups, each a hash array 
     113     */ 
     114    function list_groups($search = null) 
     115    { 
     116        $results = array(); 
     117     
     118        if (!$this->groups) 
     119            return $results; 
     120 
     121        $sql_filter = $search ? "AND " . $this->db->ilike('name', '%'.$search.'%') : ''; 
     122 
     123        $sql_result = $this->db->query( 
     124            "SELECT * FROM ".get_table_name('contactgroups'). 
     125            " WHERE del<>1". 
     126            " AND user_id=?". 
     127            $sql_filter. 
     128            " ORDER BY name", 
     129            $this->user_id); 
     130 
     131        while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { 
     132            $sql_arr['ID'] = $sql_arr['contactgroup_id']; 
     133            $results[]     = $sql_arr; 
     134        } 
     135 
     136        return $results; 
     137    } 
     138 
     139 
     140    /** 
     141     * List the current set of contact records 
     142     * 
     143     * @param  array   List of cols to show 
     144     * @param  int     Only return this number of records, use negative values for tail 
     145     * @param  boolean True to skip the count query (select only) 
     146     * @return array  Indexed list of contact records, each a hash array 
     147     */ 
     148    function list_records($cols=null, $subset=0, $nocount=false) 
     149    { 
     150        if ($nocount || $this->list_page <= 1) { 
     151            // create dummy result, we don't need a count now 
     152            $this->result = new rcube_result_set(); 
     153        } else { 
     154            // count all records 
     155            $this->result = $this->count(); 
     156        } 
     157 
     158        $start_row = $subset < 0 ? $this->result->first + $this->page_size + $subset : $this->result->first; 
     159        $length = $subset != 0 ? abs($subset) : $this->page_size; 
     160 
     161        if ($this->group_id) 
     162            $join = "LEFT JOIN ".get_table_name('contactgroupmembers')." AS m". 
     163                " ON (m.contact_id = c.".$this->primary_key.")"; 
     164 
     165        $sql_result = $this->db->limitquery( 
     166            "SELECT * FROM ".$this->db_name." AS c ".$join . 
     167            " WHERE c.del<>1" . 
     168            " AND c.user_id=?" . 
     169            ($this->group_id ? " AND m.contactgroup_id=?" : ""). 
     170            ($this->filter ? " AND (".$this->filter.")" : "") . 
     171            " ORDER BY c.name", 
     172            $start_row, 
     173            $length, 
     174            $this->user_id, 
     175            $this->group_id); 
     176 
     177        while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { 
     178            $sql_arr['ID'] = $sql_arr[$this->primary_key]; 
     179            // make sure we have a name to display 
     180            if (empty($sql_arr['name'])) 
     181                $sql_arr['name'] = $sql_arr['email']; 
     182            $this->result->add($sql_arr); 
     183        } 
     184     
     185        $cnt = count($this->result->records); 
     186 
     187        // update counter 
     188        if ($nocount) 
     189            $this->result->count = $cnt; 
     190        else if ($this->list_page <= 1) { 
     191            if ($cnt < $this->page_size && $subset == 0) 
     192                $this->result->count = $cnt; 
     193            else 
     194                $this->result->count = $this->_count(); 
     195        } 
     196     
     197        return $this->result; 
     198    } 
     199 
     200 
     201    /** 
     202     * Search contacts 
     203     * 
     204     * @param array   List of fields to search in 
     205     * @param string  Search value 
     206     * @param boolean True for strict (=), False for partial (LIKE) matching 
     207     * @param boolean True if results are requested, False if count only 
     208     * @param boolean True to skip the count query (select only) 
     209     * @return Indexed list of contact records and 'count' value 
     210     */ 
     211    function search($fields, $value, $strict=false, $select=true, $nocount=false) 
     212    { 
     213        if (!is_array($fields)) 
     214            $fields = array($fields); 
     215       
     216        $add_where = array(); 
     217        foreach ($fields as $col) { 
     218            if ($col == 'ID' || $col == $this->primary_key) { 
     219                $ids         = !is_array($value) ? explode(',', $value) : $value; 
     220                $add_where[] = 'c.' . $this->primary_key.' IN ('.join(',', $ids).')'; 
     221            } 
     222            else if ($strict) 
     223                $add_where[] = $this->db->quoteIdentifier($col).'='.$this->db->quote($value); 
     224            else 
     225                $add_where[] = $this->db->ilike($col, '%'.$value.'%'); 
     226        } 
     227     
     228        if (!empty($add_where)) { 
     229            $this->set_search_set(join(' OR ', $add_where)); 
     230            if ($select) 
     231                $this->list_records(null, 0, $nocount); 
     232            else 
     233                $this->result = $this->count(); 
     234        } 
     235 
     236        return $this->result;  
     237    } 
     238 
     239 
     240    /** 
     241     * Count number of available contacts in database 
     242     * 
     243     * @return rcube_result_set Result object 
     244     */ 
     245    function count() 
     246    { 
     247        return new rcube_result_set($this->_count(), ($this->list_page-1) * $this->page_size); 
     248    } 
     249 
     250 
     251    /** 
     252     * Count number of available contacts in database 
     253     * 
     254     * @return int Contacts count 
     255     */ 
     256    private function _count() 
     257    { 
     258        if ($this->group_id) 
     259            $join = "LEFT JOIN ".get_table_name('contactgroupmembers')." AS m". 
     260                " ON (m.contact_id=c.".$this->primary_key.")"; 
     261       
     262        // count contacts for this user 
     263        $sql_result = $this->db->query( 
     264            "SELECT COUNT(c.contact_id) AS rows". 
     265            " FROM ".$this->db_name." AS c ".$join. 
     266            " WHERE  c.del<>1". 
     267            " AND c.user_id=?". 
     268            ($this->group_id ? " AND m.contactgroup_id=?" : ""). 
     269            ($this->filter ? " AND (".$this->filter.")" : ""), 
     270            $this->user_id, 
     271            $this->group_id 
     272        ); 
     273 
     274        $sql_arr = $this->db->fetch_assoc($sql_result); 
     275        return (int) $sql_arr['rows']; 
     276    } 
     277 
     278 
     279    /** 
     280     * Return the last result set 
     281     * 
     282     * @return Result array or NULL if nothing selected yet 
     283     */ 
     284    function get_result() 
     285    { 
     286        return $this->result; 
     287    } 
    73288   
    74289   
    75   /** 
    76    * Getter for saved search properties 
    77    * 
    78    * @return mixed Search properties used by this class 
    79    */ 
    80   function get_search_set() 
    81   { 
    82     return $this->filter; 
    83   } 
    84  
    85  
    86   /** 
    87    * Setter for the current group 
    88    * (empty, has to be re-implemented by extending class) 
    89    */ 
    90   function set_group($gid) 
    91   { 
    92     $this->group_id = $gid; 
    93   } 
    94  
    95  
    96   /** 
    97    * Reset all saved results and search parameters 
    98    */ 
    99   function reset() 
    100   { 
    101     $this->result = null; 
    102     $this->filter = null; 
    103     $this->search_fields = null; 
    104     $this->search_string = null; 
    105   } 
    106    
    107   /** 
    108    * List all active contact groups of this source 
    109    * 
    110    * @param string  Search string to match group name 
    111    * @return array  Indexed list of contact groups, each a hash array 
    112    */ 
    113   function list_groups($search = null) 
    114   { 
    115     $results = array(); 
    116      
    117     if (!$this->groups) 
    118       return $results; 
     290    /** 
     291     * Get a specific contact record 
     292     * 
     293     * @param mixed record identifier(s) 
     294     * @return Result object with all record fields or False if not found 
     295     */ 
     296    function get_record($id, $assoc=false) 
     297    { 
     298        // return cached result 
     299        if ($this->result && ($first = $this->result->first()) && $first[$this->primary_key] == $id) 
     300            return $assoc ? $first : $this->result; 
    119301       
    120     $sql_filter = $search ? "AND " . $this->db->ilike('name', '%'.$search.'%') : ''; 
    121  
    122     $sql_result = $this->db->query( 
    123       "SELECT * FROM ".get_table_name('contactgroups')." 
    124        WHERE  del<>1 
    125        AND    user_id=? 
    126        $sql_filter 
    127        ORDER BY name", 
    128       $this->user_id); 
    129  
    130     while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { 
    131       $sql_arr['ID'] = $sql_arr['contactgroup_id']; 
    132       $results[] = $sql_arr; 
    133     } 
    134      
    135     return $results; 
    136   } 
    137    
    138   /** 
    139    * List the current set of contact records 
    140    * 
    141    * @param  array   List of cols to show 
    142    * @param  int     Only return this number of records, use negative values for tail 
    143    * @param  boolean True to skip the count query (select only) 
    144    * @return array  Indexed list of contact records, each a hash array 
    145    */ 
    146   function list_records($cols=null, $subset=0, $nocount=false) 
    147   { 
    148     // count contacts for this user 
    149     $this->result = $nocount ? new rcube_result_set(1) : $this->count(); 
    150     $sql_result = NULL; 
    151  
    152     // get contacts from DB 
    153     if ($this->result->count) 
    154     { 
    155       if ($this->group_id) 
    156         $join = "LEFT JOIN ".get_table_name('contactgroupmembers')." AS m". 
    157           " ON (m.contact_id=c.".$this->primary_key.")"; 
    158        
    159       $start_row = $subset < 0 ? $this->result->first + $this->page_size + $subset : $this->result->first; 
    160       $length = $subset != 0 ? abs($subset) : $this->page_size; 
    161        
    162       $sql_result = $this->db->limitquery( 
    163         "SELECT * FROM ".$this->db_name." AS c ".$join." 
    164          WHERE  c.del<>1 
    165          AND    c.user_id=?" . 
    166         ($this->group_id ? " AND m.contactgroup_id=?" : ""). 
    167         ($this->filter ? " AND (".$this->filter.")" : "") . 
    168         " ORDER BY c.name", 
    169         $start_row, 
    170         $length, 
    171         $this->user_id, 
    172         $this->group_id); 
    173     } 
    174      
    175     while ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) 
    176     { 
    177       $sql_arr['ID'] = $sql_arr[$this->primary_key]; 
    178       // make sure we have a name to display 
    179       if (empty($sql_arr['name'])) 
    180         $sql_arr['name'] = $sql_arr['email']; 
    181       $this->result->add($sql_arr); 
    182     } 
    183      
    184     if ($nocount) 
    185       $this->result->count = count($this->result->records); 
    186      
    187     return $this->result; 
    188   } 
    189  
    190  
    191   /** 
    192    * Search contacts 
    193    * 
    194    * @param array   List of fields to search in 
    195    * @param string  Search value 
    196    * @param boolean True for strict (=), False for partial (LIKE) matching 
    197    * @param boolean True if results are requested, False if count only 
    198    * @param boolean True to skip the count query (select only) 
    199    * @return Indexed list of contact records and 'count' value 
    200    */ 
    201   function search($fields, $value, $strict=false, $select=true, $nocount=false) 
    202   { 
    203     if (!is_array($fields)) 
    204       $fields = array($fields); 
    205        
    206     $add_where = array(); 
    207     foreach ($fields as $col) 
    208     { 
    209       if ($col == 'ID' || $col == $this->primary_key) 
    210       { 
    211         $ids = !is_array($value) ? explode(',', $value) : $value; 
    212         $add_where[] = 'c.' . $this->primary_key.' IN ('.join(',', $ids).')'; 
    213       } 
    214       else if ($strict) 
    215         $add_where[] = $this->db->quoteIdentifier($col).'='.$this->db->quote($value); 
    216       else 
    217         $add_where[] = $this->db->ilike($col, '%'.$value.'%'); 
    218     } 
    219      
    220     if (!empty($add_where)) 
    221     { 
    222       $this->set_search_set(join(' OR ', $add_where)); 
    223       if ($select) 
    224         $this->list_records(null, 0, $nocount); 
    225       else 
    226         $this->result = $this->count(); 
    227     } 
    228     
    229     return $this->result;  
    230   } 
    231  
    232  
    233   /** 
    234    * Count number of available contacts in database 
    235    * 
    236    * @return Result array with values for 'count' and 'first' 
    237    */ 
    238   function count() 
    239   { 
    240     if ($this->group_id) 
    241       $join = "LEFT JOIN ".get_table_name('contactgroupmembers')." AS m". 
    242         " ON (m.contact_id=c.".$this->primary_key.")"; 
    243        
    244     // count contacts for this user 
    245     $sql_result = $this->db->query( 
    246       "SELECT COUNT(c.contact_id) AS rows 
    247        FROM ".$this->db_name." AS c ".$join." 
    248        WHERE  c.del<>1 
    249        AND    c.user_id=?". 
    250        ($this->group_id ? " AND m.contactgroup_id=?" : ""). 
    251        ($this->filter ? " AND (".$this->filter.")" : ""), 
    252       $this->user_id, 
    253       $this->group_id); 
    254  
    255     $sql_arr = $this->db->fetch_assoc($sql_result); 
    256     return new rcube_result_set($sql_arr['rows'], ($this->list_page-1) * $this->page_size);; 
    257   } 
    258  
    259  
    260   /** 
    261    * Return the last result set 
    262    * 
    263    * @return Result array or NULL if nothing selected yet 
    264    */ 
    265   function get_result() 
    266   { 
    267     return $this->result; 
    268   } 
    269    
    270    
    271   /** 
    272    * Get a specific contact record 
    273    * 
    274    * @param mixed record identifier(s) 
    275    * @return Result object with all record fields or False if not found 
    276    */ 
    277   function get_record($id, $assoc=false) 
    278   { 
    279     // return cached result 
    280     if ($this->result && ($first = $this->result->first()) && $first[$this->primary_key] == $id) 
    281       return $assoc ? $first : $this->result; 
    282        
    283     $this->db->query( 
    284       "SELECT * FROM ".$this->db_name." 
    285        WHERE  contact_id=? 
    286        AND    user_id=? 
    287        AND    del<>1", 
    288       $id, 
    289       $this->user_id); 
    290  
    291     if ($sql_arr = $this->db->fetch_assoc()) 
    292     { 
    293       $sql_arr['ID'] = $sql_arr[$this->primary_key]; 
    294       $this->result = new rcube_result_set(1); 
    295       $this->result->add($sql_arr); 
    296     } 
    297  
    298     return $assoc && $sql_arr ? $sql_arr : $this->result; 
    299   } 
    300    
    301    
    302   /** 
    303    * Create a new contact record 
    304    * 
    305    * @param array Assoziative array with save data 
    306    * @return The created record ID on success, False on error 
    307    */ 
    308   function insert($save_data, $check=false) 
    309   { 
    310     if (is_object($save_data) && is_a($save_data, rcube_result_set)) 
    311       return $this->insert_recset($save_data, $check); 
    312  
    313     $insert_id = $existing = false; 
    314  
    315     if ($check) 
    316       $existing = $this->search('email', $save_data['email'], true, false); 
    317  
    318     $a_insert_cols = $a_insert_values = array(); 
    319     foreach ($this->table_cols as $col) 
    320       if (isset($save_data[$col])) 
    321       { 
    322         $a_insert_cols[] = $this->db->quoteIdentifier($col); 
    323         $a_insert_values[] = $this->db->quote($save_data[$col]); 
    324       } 
    325  
    326     if (!$existing->count && !empty($a_insert_cols)) 
    327     { 
    328       $this->db->query( 
    329         "INSERT INTO ".$this->db_name." 
    330          (user_id, changed, del, ".join(', ', $a_insert_cols).") 
    331          VALUES (".intval($this->user_id).", ".$this->db->now().", 0, ".join(', ', $a_insert_values).")" 
     302        $this->db->query( 
     303            "SELECT * FROM ".$this->db_name. 
     304            " WHERE contact_id=?". 
     305                " AND user_id=?". 
     306                " AND del<>1", 
     307            $id, 
     308            $this->user_id 
    332309        ); 
    333          
    334       $insert_id = $this->db->insert_id('contacts'); 
    335     } 
    336      
    337     // also add the newly created contact to the active group 
    338     if ($insert_id && $this->group_id) 
    339       $this->add_to_group($this->group_id, $insert_id); 
    340  
    341     return $insert_id; 
    342   } 
    343  
    344  
    345   /** 
    346    * Insert new contacts for each row in set 
    347    */ 
    348   function insert_recset($result, $check=false) 
    349   { 
    350     $ids = array(); 
    351     while ($row = $result->next()) 
    352     { 
    353       if ($insert = $this->insert($row, $check)) 
    354         $ids[] = $insert; 
    355     } 
    356     return $ids; 
    357   } 
    358    
    359    
    360   /** 
    361    * Update a specific contact record 
    362    * 
    363    * @param mixed Record identifier 
    364    * @param array Assoziative array with save data 
    365    * @return True on success, False on error 
    366    */ 
    367   function update($id, $save_cols) 
    368   { 
    369     $updated = false; 
    370     $write_sql = array(); 
    371     foreach ($this->table_cols as $col) 
    372       if (isset($save_cols[$col])) 
    373         $write_sql[] = sprintf("%s=%s", $this->db->quoteIdentifier($col), $this->db->quote($save_cols[$col])); 
    374  
    375     if (!empty($write_sql)) 
    376     { 
    377       $this->db->query( 
    378         "UPDATE ".$this->db_name." 
    379          SET    changed=".$this->db->now().", ".join(', ', $write_sql)." 
    380          WHERE  contact_id=? 
    381          AND    user_id=? 
    382          AND    del<>1", 
    383         $id, 
    384         $this->user_id); 
    385  
    386       $updated = $this->db->affected_rows(); 
    387     } 
    388      
    389     return $updated; 
    390   } 
    391    
    392    
    393   /** 
    394    * Mark one or more contact records as deleted 
    395    * 
    396    * @param array  Record identifiers 
    397    */ 
    398   function delete($ids) 
    399   { 
    400     if (is_array($ids)) 
    401       $ids = join(',', $ids); 
    402  
    403     // flag record as deleted 
    404     $this->db->query( 
    405       "UPDATE ".$this->db_name." 
    406        SET    del=1, changed=".$this->db->now()." 
    407        WHERE  user_id=? 
    408        AND    contact_id IN (".$ids.")", 
    409       $this->user_id); 
    410  
    411     return $this->db->affected_rows(); 
    412   } 
    413    
    414    
    415   /** 
    416    * Remove all records from the database 
    417    */ 
    418   function delete_all() 
    419   { 
    420     $this->db->query("DELETE FROM {$this->db_name} WHERE user_id=?", $this->user_id); 
    421     return $this->db->affected_rows(); 
    422   } 
    423  
    424  
    425   /** 
    426    * Create a contact group with the given name 
    427    * 
    428    * @param string The group name 
    429    * @return False on error, array with record props in success 
    430    */ 
    431   function create_group($name) 
    432   { 
    433     $result = false; 
    434  
    435     // make sure we have a unique name 
    436     $name = $this->unique_groupname($name); 
    437      
    438     $this->db->query( 
    439       "INSERT INTO ".get_table_name('contactgroups')." (user_id, changed, name) 
    440        VALUES (".intval($this->user_id).", ".$this->db->now().", ".$this->db->quote($name).")" 
    441       ); 
    442      
    443     if ($insert_id = $this->db->insert_id('contactgroups')) 
    444       $result = array('id' => $insert_id, 'name' => $name); 
    445      
    446     return $result; 
    447   } 
    448  
    449   /** 
    450    * Delete the given group (and all linked group members) 
    451    * 
    452    * @param string Group identifier 
    453    * @return boolean True on success, false if no data was changed 
    454    */ 
    455   function delete_group($gid) 
    456   { 
    457     // flag group record as deleted 
    458     $sql_result = $this->db->query( 
    459       "UPDATE ".get_table_name('contactgroups')." 
    460        SET del=1, changed=".$this->db->now()." 
    461        WHERE  contactgroup_id=?", 
    462       $gid); 
    463      
    464     return $this->db->affected_rows(); 
    465   } 
    466    
    467   /** 
    468    * Rename a specific contact group 
    469    * 
    470    * @param string Group identifier 
    471    * @param string New name to set for this group 
    472    * @return boolean New name on success, false if no data was changed 
    473    */ 
    474   function rename_group($gid, $newname) 
    475   { 
    476     // make sure we have a unique name 
    477     $name = $this->unique_groupname($newname); 
    478      
    479     $sql_result = $this->db->query( 
    480       "UPDATE ".get_table_name('contactgroups')." 
    481        SET name=".$this->db->quote($name).", changed=".$this->db->now()." 
    482        WHERE  contactgroup_id=?", 
    483       $gid); 
    484      
    485     return $this->db->affected_rows() ? $name : false; 
    486   } 
    487  
    488   /** 
    489    * Add the given contact records the a certain group 
    490    * 
    491    * @param string  Group identifier 
    492    * @param array   List of contact identifiers to be added 
    493    * @return int    Number of contacts added  
    494    */ 
    495   function add_to_group($group_id, $ids) 
    496   { 
    497     if (!is_array($ids)) 
    498       $ids = explode(',', $ids); 
    499      
    500     $added = 0; 
    501      
    502     foreach ($ids as $contact_id) { 
    503       $sql_result = $this->db->query( 
    504         "SELECT 1 FROM ".get_table_name('contactgroupmembers')." 
    505          WHERE  contactgroup_id=? 
    506          AND    contact_id=?", 
    507       $group_id, 
    508       $contact_id); 
    509        
    510       if (!$this->db->num_rows($sql_result)) { 
     310 
     311        if ($sql_arr = $this->db->fetch_assoc()) { 
     312            $sql_arr['ID'] = $sql_arr[$this->primary_key]; 
     313            $this->result = new rcube_result_set(1); 
     314            $this->result->add($sql_arr); 
     315        } 
     316 
     317        return $assoc && $sql_arr ? $sql_arr : $this->result; 
     318    } 
     319 
     320 
     321    /** 
     322     * Create a new contact record 
     323     * 
     324     * @param array Assoziative array with save data 
     325     * @return The created record ID on success, False on error 
     326     */ 
     327    function insert($save_data, $check=false) 
     328    { 
     329        if (is_object($save_data) && is_a($save_data, rcube_result_set)) 
     330            return $this->insert_recset($save_data, $check); 
     331 
     332        $insert_id = $existing = false; 
     333 
     334        if ($check) 
     335            $existing = $this->search('email', $save_data['email'], true, false); 
     336 
     337        $a_insert_cols = $a_insert_values = array(); 
     338 
     339        foreach ($this->table_cols as $col) 
     340            if (isset($save_data[$col])) { 
     341                $a_insert_cols[]   = $this->db->quoteIdentifier($col); 
     342                $a_insert_values[] = $this->db->quote($save_data[$col]); 
     343            } 
     344 
     345        if (!$existing->count && !empty($a_insert_cols)) { 
     346            $this->db->query( 
     347                "INSERT INTO ".$this->db_name. 
     348                " (user_id, changed, del, ".join(', ', $a_insert_cols).")". 
     349                " VALUES (".intval($this->user_id).", ".$this->db->now().", 0, ".join(', ', $a_insert_values).")" 
     350            ); 
     351 
     352            $insert_id = $this->db->insert_id('contacts'); 
     353        } 
     354 
     355        // also add the newly created contact to the active group 
     356        if ($insert_id && $this->group_id) 
     357            $this->add_to_group($this->group_id, $insert_id); 
     358 
     359        return $insert_id; 
     360    } 
     361 
     362 
     363    /** 
     364     * Insert new contacts for each row in set 
     365     */ 
     366    function insert_recset($result, $check=false) 
     367    { 
     368        $ids = array(); 
     369        while ($row = $result->next()) { 
     370            if ($insert = $this->insert($row, $check)) 
     371                $ids[] = $insert; 
     372        } 
     373        return $ids; 
     374    } 
     375 
     376 
     377    /** 
     378     * Update a specific contact record 
     379     * 
     380     * @param mixed Record identifier 
     381     * @param array Assoziative array with save data 
     382     * @return True on success, False on error 
     383     */ 
     384    function update($id, $save_cols) 
     385    { 
     386        $updated = false; 
     387        $write_sql = array(); 
     388 
     389        foreach ($this->table_cols as $col) 
     390            if (isset($save_cols[$col])) 
     391                $write_sql[] = sprintf("%s=%s", $this->db->quoteIdentifier($col), 
     392                    $this->db->quote($save_cols[$col])); 
     393 
     394        if (!empty($write_sql)) { 
     395            $this->db->query( 
     396                "UPDATE ".$this->db_name. 
     397                " SET changed=".$this->db->now().", ".join(', ', $write_sql). 
     398                " WHERE contact_id=?". 
     399                    " AND user_id=?". 
     400                    " AND del<>1", 
     401                $id, 
     402                $this->user_id 
     403            ); 
     404 
     405            $updated = $this->db->affected_rows(); 
     406        } 
     407     
     408        return $updated; 
     409    } 
     410 
     411 
     412    /** 
     413     * Mark one or more contact records as deleted 
     414     * 
     415     * @param array  Record identifiers 
     416     */ 
     417    function delete($ids) 
     418    { 
     419        if (is_array($ids)) 
     420            $ids = join(',', $ids); 
     421 
     422        $ids = join(',', array_map(array($this->db, 'quote'), $ids)); 
     423 
     424        // flag record as deleted 
    511425        $this->db->query( 
    512           "INSERT INTO ".get_table_name('contactgroupmembers')." (contactgroup_id, contact_id, created) 
    513            VALUES (".intval($group_id).", ".intval($contact_id).", ".$this->db->now().")" 
     426            "UPDATE ".$this->db_name. 
     427            " SET del=1, changed=".$this->db->now(). 
     428            " WHERE user_id=?". 
     429                " AND contact_id IN ($ids)", 
     430            $this->user_id 
    514431        ); 
    515         if (!$this->db->db_error) 
    516           $added++; 
    517       } 
    518     } 
    519      
    520     return $added; 
    521   } 
    522    
    523    
    524   /** 
    525    * Remove the given contact records from a certain group 
    526    * 
    527    * @param string  Group identifier 
    528    * @param array   List of contact identifiers to be removed 
    529    * @return int    Number of deleted group members 
    530    */ 
    531   function remove_from_group($group_id, $ids) 
    532   { 
    533     if (!is_array($ids)) 
    534       $ids = explode(',', $ids); 
    535      
    536     $sql_result = $this->db->query( 
    537       "DELETE FROM ".get_table_name('contactgroupmembers')." 
    538        WHERE  contactgroup_id=? 
    539        AND    contact_id IN (".join(',', array_map(array($this->db, 'quote'), $ids)).")", 
    540       $group_id); 
    541      
    542     return $this->db->affected_rows(); 
    543   } 
    544    
    545   /** 
    546    * Check for existing groups with the same name 
    547    * 
    548    * @param string Name to check 
    549    * @return string A group name which is unique for the current use 
    550    */ 
    551   private function unique_groupname($name) 
    552   { 
    553     $checkname = $name; 
    554     $num = 2; $hit = false; 
    555      
    556     do { 
    557       $sql_result = $this->db->query( 
    558         "SELECT 1 FROM ".get_table_name('contactgroups')." 
    559          WHERE  del<>1 
    560          AND    user_id=? 
    561          AND    name LIKE ?", 
    562         $this->user_id, 
    563         $checkname); 
    564      
    565       // append number to make name unique 
    566       if ($hit = $this->db->num_rows($sql_result)) 
    567         $checkname = $name . ' ' . $num++; 
    568     } while ($hit > 0); 
    569      
    570     return $checkname; 
    571   } 
     432 
     433        return $this->db->affected_rows(); 
     434    } 
     435 
     436 
     437    /** 
     438     * Remove all records from the database 
     439     */ 
     440    function delete_all() 
     441    { 
     442        $this->db->query("DELETE FROM {$this->db_name} WHERE user_id=?", $this->user_id); 
     443        return $this->db->affected_rows(); 
     444    } 
     445 
     446 
     447    /** 
     448     * Create a contact group with the given name 
     449     * 
     450     * @param string The group name 
     451     * @return False on error, array with record props in success 
     452     */ 
     453    function create_group($name) 
     454    { 
     455        $result = false; 
     456 
     457        // make sure we have a unique name 
     458        $name = $this->unique_groupname($name); 
     459     
     460        $this->db->query( 
     461            "INSERT INTO ".get_table_name('contactgroups'). 
     462            " (user_id, changed, name)". 
     463            " VALUES (".intval($this->user_id).", ".$this->db->now().", ".$this->db->quote($name).")" 
     464        ); 
     465     
     466        if ($insert_id = $this->db->insert_id('contactgroups')) 
     467            $result = array('id' => $insert_id, 'name' => $name); 
     468     
     469        return $result; 
     470    } 
     471 
     472 
     473    /** 
     474     * Delete the given group (and all linked group members) 
     475     * 
     476     * @param string Group identifier 
     477     * @return boolean True on success, false if no data was changed 
     478     */ 
     479    function delete_group($gid) 
     480    { 
     481        // flag group record as deleted 
     482        $sql_result = $this->db->query( 
     483            "UPDATE ".get_table_name('contactgroups'). 
     484            " SET del=1, changed=".$this->db->now(). 
     485            " WHERE contactgroup_id=?", 
     486            $gid 
     487        ); 
     488 
     489        return $this->db->affected_rows(); 
     490    } 
     491 
     492 
     493    /** 
     494     * Rename a specific contact group 
     495     * 
     496     * @param string Group identifier 
     497     * @param string New name to set for this group 
     498     * @return boolean New name on success, false if no data was changed 
     499     */ 
     500    function rename_group($gid, $newname) 
     501    { 
     502        // make sure we have a unique name 
     503        $name = $this->unique_groupname($newname); 
     504     
     505        $sql_result = $this->db->query( 
     506            "UPDATE ".get_table_name('contactgroups'). 
     507            " SET name=?, changed=".$this->db->now(). 
     508            " WHERE contactgroup_id=?", 
     509            $name, $gid 
     510        ); 
     511 
     512        return $this->db->affected_rows() ? $name : false; 
     513    } 
     514 
     515 
     516    /** 
     517     * Add the given contact records the a certain group 
     518     * 
     519     * @param string  Group identifier 
     520     * @param array   List of contact identifiers to be added 
     521     * @return int    Number of contacts added  
     522     */ 
     523    function add_to_group($group_id, $ids) 
     524    { 
     525        if (!is_array($ids)) 
     526            $ids = explode(',', $ids); 
     527     
     528        $added = 0; 
     529     
     530        foreach ($ids as $contact_id) { 
     531            $sql_result = $this->db->query( 
     532                "SELECT 1 FROM ".get_table_name('contactgroupmembers'). 
     533                " WHERE contactgroup_id=?". 
     534                    " AND contact_id=?", 
     535                $group_id, 
     536                $contact_id 
     537            ); 
     538 
     539            if (!$this->db->num_rows($sql_result)) { 
     540                $this->db->query( 
     541                    "INSERT INTO ".get_table_name('contactgroupmembers'). 
     542                    " (contactgroup_id, contact_id, created)". 
     543                    " VALUES (?, ?, ".$this->db->now().")", 
     544                    $group_id, 
     545                    $contact_id 
     546                ); 
     547 
     548                if (!$this->db->db_error) 
     549                    $added++; 
     550            } 
     551        } 
     552 
     553        return $added; 
     554    } 
     555 
     556 
     557    /** 
     558     * Remove the given contact records from a certain group 
     559     * 
     560     * @param string  Group identifier 
     561     * @param array   List of contact identifiers to be removed 
     562     * @return int    Number of deleted group members 
     563     */ 
     564    function remove_from_group($group_id, $ids) 
     565    { 
     566        if (!is_array($ids)) 
     567            $ids = explode(',', $ids); 
     568 
     569        $ids = join(',', array_map(array($this->db, 'quote'), $ids)); 
     570     
     571        $sql_result = $this->db->query( 
     572            "DELETE FROM ".get_table_name('contactgroupmembers'). 
     573            " WHERE contactgroup_id=?". 
     574                " AND contact_id IN ($ids)", 
     575            $group_id 
     576        ); 
     577 
     578        return $this->db->affected_rows(); 
     579    } 
     580 
     581 
     582    /** 
     583     * Check for existing groups with the same name 
     584     * 
     585     * @param string Name to check 
     586     * @return string A group name which is unique for the current use 
     587     */ 
     588    private function unique_groupname($name) 
     589    { 
     590        $checkname = $name; 
     591        $num = 2; $hit = false; 
     592     
     593        do { 
     594            $sql_result = $this->db->query( 
     595                "SELECT 1 FROM ".get_table_name('contactgroups'). 
     596                " WHERE del<>1". 
     597                    " AND user_id=?". 
     598                    " AND name LIKE ?", 
     599                $this->user_id, 
     600                $checkname); 
     601     
     602            // append number to make name unique 
     603            if ($hit = $this->db->num_rows($sql_result)) 
     604                $checkname = $name . ' ' . $num++; 
     605        } while ($hit > 0); 
     606     
     607        return $checkname; 
     608    } 
     609 
    572610} 
Note: See TracChangeset for help on using the changeset viewer.