source: github/program/include/rcube_addressbook.php @ 71e8cc3

HEADcourier-fixdev-browser-capabilitiespdorelease-0.6release-0.7release-0.8
Last change on this file since 71e8cc3 was 71e8cc3, checked in by alecpl <alec@…>, 22 months ago
  • Fixed display name on contact lists
  • Property mode set to 100644
File size: 13.7 KB
Line 
1<?php
2
3/*
4 +-----------------------------------------------------------------------+
5 | program/include/rcube_addressbook.php                                 |
6 |                                                                       |
7 | This file is part of the Roundcube Webmail client                     |
8 | Copyright (C) 2006-2011, The Roundcube Dev Team                       |
9 | Licensed under the GNU GPL                                            |
10 |                                                                       |
11 | PURPOSE:                                                              |
12 |   Interface to the local address book database                        |
13 |                                                                       |
14 +-----------------------------------------------------------------------+
15 | Author: Thomas Bruederli <roundcube@gmail.com>                        |
16 +-----------------------------------------------------------------------+
17
18 $Id$
19
20*/
21
22
23/**
24 * Abstract skeleton of an address book/repository
25 *
26 * @package Addressbook
27 */
28abstract class rcube_addressbook
29{
30    /** constants for error reporting **/
31    const ERROR_READ_ONLY = 1;
32    const ERROR_NO_CONNECTION = 2;
33    const ERROR_INCOMPLETE = 3;
34    const ERROR_SAVING = 4;
35    const ERROR_SEARCH = 5;
36
37    /** public properties (mandatory) */
38    public $primary_key;
39    public $groups = false;
40    public $readonly = true;
41    public $undelete = false;
42    public $ready = false;
43    public $group_id = null;
44    public $list_page = 1;
45    public $page_size = 10;
46    public $coltypes = array('name' => array('limit'=>1), 'firstname' => array('limit'=>1), 'surname' => array('limit'=>1), 'email' => array('limit'=>1));
47
48    protected $error;
49
50    /**
51     * Returns addressbook name (e.g. for addressbooks listing)
52     */
53    abstract function get_name();
54
55    /**
56     * Save a search string for future listings
57     *
58     * @param mixed Search params to use in listing method, obtained by get_search_set()
59     */
60    abstract function set_search_set($filter);
61
62    /**
63     * Getter for saved search properties
64     *
65     * @return mixed Search properties used by this class
66     */
67    abstract function get_search_set();
68
69    /**
70     * Reset saved results and search parameters
71     */
72    abstract function reset();
73
74    /**
75     * Refresh saved search set after data has changed
76     *
77     * @return mixed New search set
78     */
79    function refresh_search()
80    {
81        return $this->get_search_set();
82    }
83
84    /**
85     * List the current set of contact records
86     *
87     * @param  array  List of cols to show
88     * @param  int    Only return this number of records, use negative values for tail
89     * @return array  Indexed list of contact records, each a hash array
90     */
91    abstract function list_records($cols=null, $subset=0);
92
93    /**
94     * Search records
95     *
96     * @param array   List of fields to search in
97     * @param string  Search value
98     * @param boolean True if results are requested, False if count only
99     * @param boolean True to skip the count query (select only)
100     * @param array   List of fields that cannot be empty
101     * @return object rcube_result_set List of contact records and 'count' value
102     */
103    abstract function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array());
104
105    /**
106     * Count number of available contacts in database
107     *
108     * @return rcube_result_set Result set with values for 'count' and 'first'
109     */
110    abstract function count();
111
112    /**
113     * Return the last result set
114     *
115     * @return rcube_result_set Current result set or NULL if nothing selected yet
116     */
117    abstract function get_result();
118
119    /**
120     * Get a specific contact record
121     *
122     * @param mixed record identifier(s)
123     * @param boolean True to return record as associative array, otherwise a result set is returned
124     *
125     * @return mixed Result object with all record fields or False if not found
126     */
127    abstract function get_record($id, $assoc=false);
128
129    /**
130     * Returns the last error occured (e.g. when updating/inserting failed)
131     *
132     * @return array Hash array with the following fields: type, message
133     */
134    function get_error()
135    {
136      return $this->error;
137    }
138
139    /**
140     * Setter for errors for internal use
141     *
142     * @param int Error type (one of this class' error constants)
143     * @param string Error message (name of a text label)
144     */
145    protected function set_error($type, $message)
146    {
147      $this->error = array('type' => $type, 'message' => $message);
148    }
149
150    /**
151     * Close connection to source
152     * Called on script shutdown
153     */
154    function close() { }
155
156    /**
157     * Set internal list page
158     *
159     * @param  number  Page number to list
160     * @access public
161     */
162    function set_page($page)
163    {
164        $this->list_page = (int)$page;
165    }
166
167    /**
168     * Set internal page size
169     *
170     * @param  number  Number of messages to display on one page
171     * @access public
172     */
173    function set_pagesize($size)
174    {
175        $this->page_size = (int)$size;
176    }
177
178
179    /**
180     * Check the given data before saving.
181     * If input isn't valid, the message to display can be fetched using get_error()
182     *
183     * @param array Assoziative array with data to save
184     * @return boolean True if input is valid, False if not.
185     */
186    public function validate($save_data)
187    {
188        // check validity of email addresses
189        foreach ($this->get_col_values('email', $save_data, true) as $email) {
190            if (strlen($email)) {
191                if (!check_email(rcube_idn_to_ascii($email))) {
192                    $this->set_error('warning', rcube_label(array('name' => 'emailformaterror', 'vars' => array('email' => $email))));
193                    return false;
194                }
195            }
196        }
197
198        return true;
199    }
200
201
202    /**
203     * Create a new contact record
204     *
205     * @param array Assoziative array with save data
206     *  Keys:   Field name with optional section in the form FIELD:SECTION
207     *  Values: Field value. Can be either a string or an array of strings for multiple values
208     * @param boolean True to check for duplicates first
209     * @return mixed The created record ID on success, False on error
210     */
211    function insert($save_data, $check=false)
212    {
213        /* empty for read-only address books */
214    }
215
216    /**
217     * Create new contact records for every item in the record set
218     *
219     * @param object rcube_result_set Recordset to insert
220     * @param boolean True to check for duplicates first
221     * @return array List of created record IDs
222     */
223    function insertMultiple($recset, $check=false)
224    {
225        $ids = array();
226        if (is_object($recset) && is_a($recset, rcube_result_set)) {
227            while ($row = $recset->next()) {
228                if ($insert = $this->insert($row, $check))
229                    $ids[] = $insert;
230            }
231        }
232        return $ids;
233    }
234
235    /**
236     * Update a specific contact record
237     *
238     * @param mixed Record identifier
239     * @param array Assoziative array with save data
240     *  Keys:   Field name with optional section in the form FIELD:SECTION
241     *  Values: Field value. Can be either a string or an array of strings for multiple values
242     * @return boolean True on success, False on error
243     */
244    function update($id, $save_cols)
245    {
246        /* empty for read-only address books */
247    }
248
249    /**
250     * Mark one or more contact records as deleted
251     *
252     * @param array  Record identifiers
253     * @param bool   Remove records irreversible (see self::undelete)
254     */
255    function delete($ids, $force=true)
256    {
257        /* empty for read-only address books */
258    }
259
260    /**
261     * Unmark delete flag on contact record(s)
262     *
263     * @param array  Record identifiers
264     */
265    function undelete($ids)
266    {
267        /* empty for read-only address books */
268    }
269
270    /**
271     * Mark all records in database as deleted
272     */
273    function delete_all()
274    {
275        /* empty for read-only address books */
276    }
277
278    /**
279     * Setter for the current group
280     * (empty, has to be re-implemented by extending class)
281     */
282    function set_group($gid) { }
283
284    /**
285     * List all active contact groups of this source
286     *
287     * @param string  Optional search string to match group name
288     * @return array  Indexed list of contact groups, each a hash array
289     */
290    function list_groups($search = null)
291    {
292        /* empty for address books don't supporting groups */
293        return array();
294    }
295
296    /**
297     * Create a contact group with the given name
298     *
299     * @param string The group name
300     * @return mixed False on error, array with record props in success
301     */
302    function create_group($name)
303    {
304        /* empty for address books don't supporting groups */
305        return false;
306    }
307
308    /**
309     * Delete the given group and all linked group members
310     *
311     * @param string Group identifier
312     * @return boolean True on success, false if no data was changed
313     */
314    function delete_group($gid)
315    {
316        /* empty for address books don't supporting groups */
317        return false;
318    }
319
320    /**
321     * Rename a specific contact group
322     *
323     * @param string Group identifier
324     * @param string New name to set for this group
325     * @param string New group identifier (if changed, otherwise don't set)
326     * @return boolean New name on success, false if no data was changed
327     */
328    function rename_group($gid, $newname, &$newid)
329    {
330        /* empty for address books don't supporting groups */
331        return false;
332    }
333
334    /**
335     * Add the given contact records the a certain group
336     *
337     * @param string  Group identifier
338     * @param array   List of contact identifiers to be added
339     * @return int    Number of contacts added
340     */
341    function add_to_group($group_id, $ids)
342    {
343        /* empty for address books don't supporting groups */
344        return 0;
345    }
346
347    /**
348     * Remove the given contact records from a certain group
349     *
350     * @param string  Group identifier
351     * @param array   List of contact identifiers to be removed
352     * @return int    Number of deleted group members
353     */
354    function remove_from_group($group_id, $ids)
355    {
356        /* empty for address books don't supporting groups */
357        return 0;
358    }
359
360    /**
361     * Get group assignments of a specific contact record
362     *
363     * @param mixed Record identifier
364     *
365     * @return array List of assigned groups as ID=>Name pairs
366     * @since 0.5-beta
367     */
368    function get_record_groups($id)
369    {
370        /* empty for address books don't supporting groups */
371        return array();
372    }
373
374
375    /**
376     * Utility function to return all values of a certain data column
377     * either as flat list or grouped by subtype
378     *
379     * @param string Col name
380     * @param array  Record data array as used for saving
381     * @param boolean True to return one array with all values, False for hash array with values grouped by type
382     * @return array List of column values
383     */
384    function get_col_values($col, $data, $flat = false)
385    {
386        $out = array();
387        foreach ($data as $c => $values) {
388            if (strpos($c, $col) === 0) {
389                if ($flat) {
390                    $out = array_merge($out, (array)$values);
391                }
392                else {
393                    list($f, $type) = explode(':', $c);
394                    $out[$type] = array_merge((array)$out[$type], (array)$values);
395                }
396            }
397        }
398
399        return $out;
400    }
401
402
403    /**
404     * Normalize the given string for fulltext search.
405     * Currently only optimized for Latin-1 characters; to be extended
406     *
407     * @param string Input string (UTF-8)
408     * @return string Normalized string
409     */
410    protected static function normalize_string($str)
411    {
412        // split by words
413        $arr = explode(" ", preg_replace(
414            array('/[\s;\+\-\/]+/i', '/(\d)[-.\s]+(\d)/', '/\s\w{1,3}\s/'),
415            array(' ', '\\1\\2', ' '),
416            $str));
417
418        foreach ($arr as $i => $part) {
419            if (utf8_encode(utf8_decode($part)) == $part) {  // is latin-1 ?
420                $arr[$i] = utf8_encode(strtr(strtolower(strtr(utf8_decode($part),
421                    'ÇçäâàåéêëèïîìÅÉöôòüûùÿøØáíóúñÑÁÂÀãÃÊËÈÍÎÏÓÔõÕÚÛÙýÝ',
422                    'ccaaaaeeeeiiiaeooouuuyooaiounnaaaaaeeeiiioooouuuyy')),
423                    array('ß' => 'ss', 'ae' => 'a', 'oe' => 'o', 'ue' => 'u')));
424            }
425            else
426                $arr[$i] = mb_strtolower($part);
427        }
428
429        return join(" ", $arr);
430    }
431
432
433    /**
434     * Compose a valid display name from the given structured contact data
435     *
436     * @param array  Hash array with contact data as key-value pairs
437     * @param bool   The name will be used on the list
438     *
439     * @return string Display name
440     */
441    public static function compose_display_name($contact, $list_mode = false)
442    {
443        $contact = rcmail::get_instance()->plugins->exec_hook('contact_displayname', $contact);
444        $fn = $contact['name'];
445
446        if (!$fn)
447            $fn = join(' ', array_filter(array($contact['prefix'], $contact['firstname'], $contact['middlename'], $contact['surname'], $contact['suffix'])));
448
449        // use email address part for name
450        $email = is_array($contact['email']) ? $contact['email'][0] : $contact['email'];
451
452        if ($email && (empty($fn) || $fn == $email)) {
453            // Use full email address on contacts list
454            if ($list_mode)
455                return $email;
456
457            list($emailname) = explode('@', $email);
458            if (preg_match('/(.*)[\.\-\_](.*)/', $emailname, $match))
459                $fn = trim(ucfirst($match[1]).' '.ucfirst($match[2]));
460            else
461                $fn = ucfirst($emailname);
462        }
463
464        return $fn;
465    }
466
467}
468
Note: See TracBrowser for help on using the repository browser.