source: subversion/trunk/plugins/kolab_addressbook/rcube_kolab_contacts.php @ 4273

Last change on this file since 4273 was 4273, checked in by thomasb, 2 years ago

Implement basic searching

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Date Author Revision
File size: 26.8 KB
Line 
1<?php
2
3
4/**
5 * Backend class for a custom address book
6 *
7 * This part of the Roundcube+Kolab integration and connects the
8 * rcube_addressbook interface with the rcube_kolab wrapper for Kolab_Storage
9 *
10 * @author Thomas Bruederli
11 * @see rcube_addressbook
12 */
13class rcube_kolab_contacts extends rcube_addressbook
14{
15    public $primary_key = 'ID';
16    public $readonly = false;
17    public $groups = true;
18    public $coltypes = array(
19      'name'         => array('limit' => 1),
20      'firstname'    => array('limit' => 1),
21      'surname'      => array('limit' => 1),
22      'middlename'   => array('limit' => 1),
23      'prefix'       => array('limit' => 1),
24      'suffix'       => array('limit' => 1),
25      'nickname'     => array('limit' => 1),
26      'jobtitle'     => array('limit' => 1),
27      'organization' => array('limit' => 1),
28      'department'   => array('limit' => 1),
29      'gender'       => array('limit' => 1),
30      'initials'     => array('type' => 'text', 'size' => 6, 'limit' => 1, 'label' => 'kolab_addressbook.initials'),
31      'email'        => array('subtypes' => null),
32      'phone'        => array(),
33      'im'           => array('limit' => 1),
34      'website'      => array('limit' => 1, 'subtypes' => null),
35      'address'      => array('limit' => 2, 'subtypes' => array('home','business')),
36      'birthday'     => array('limit' => 1),
37      'anniversary'  => array('type' => 'date', 'size' => 12, 'limit' => 1, 'label' => 'kolab_addressbook.anniversary'),
38      // TODO: define more Kolab-specific fields such as: office-location, profession, manager-name, assistant, spouse-name, children, language, latitude, longitude, pgp-publickey, free-busy-url
39      'notes'        => array(),
40    );
41   
42    private $gid;
43    private $imap;
44    private $kolab;
45    private $folder;
46    private $contactstorage;
47    private $liststorage;
48    private $contacts;
49    private $distlists;
50    private $groupmembers;
51    private $id2uid;
52    private $filter;
53    private $result;
54    private $imap_folder = 'INBOX/Contacts';
55    private $gender_map = array(0 => 'male', 1 => 'female');
56    private $phonetypemap = array('home' => 'home1', 'work' => 'business1', 'work2' => 'business2', 'workfax' => 'businessfax');
57    private $addresstypemap = array('work' => 'business');
58    private $fieldmap = array(
59      // kolab       => roundcube
60      'full-name'    => 'name',
61      'given-name'   => 'firstname',
62      'middle-names' => 'middlename',
63      'last-name'    => 'surname',
64      'prefix'       => 'prefix',
65      'suffix'       => 'suffix',
66      'nick-name'    => 'nickname',
67      'organization' => 'organization',
68      'department'   => 'department',
69      'job-title'    => 'jobtitle',
70      'initials'     => 'initials',
71      'birthday'     => 'birthday',
72      'anniversary'  => 'anniversary',
73      'im-address'   => 'im:aim',
74      'web-page'     => 'website',
75      'body'         => 'notes',
76    );
77
78
79    public function __construct($imap_folder = null)
80    {
81        if ($imap_folder)
82            $this->imap_folder = $imap_folder;
83           
84        // extend coltypes configuration
85        $format = rcube_kolab::get_format('contact');
86        $this->coltypes['phone']['subtypes'] = $format->_phone_types;
87        $this->coltypes['address']['subtypes'] = $format->_address_types;
88       
89        // set localized labels for proprietary cols
90        foreach ($this->coltypes as $col => $prop) {
91            if (is_string($prop['label']))
92                $this->coltypes[$col]['label'] = rcube_label($prop['label']);
93        }
94       
95        // fetch objects from the given IMAP folder
96        $this->contactstorage = rcube_kolab::get_storage($this->imap_folder);
97        $this->liststorage = rcube_kolab::get_storage($this->imap_folder, 'distributionlist');
98
99        $this->ready = !PEAR::isError($this->contactstorage) && !PEAR::isError($this->liststorage);
100    }
101
102
103    /**
104     * Getter for the address book name to be displayed
105     *
106     * @return string Name of this address book
107     */
108    public function get_name()
109    {
110        return strtr(preg_replace('!^(INBOX|user)/!i', '', $this->imap_folder), '/', ':');
111    }
112
113
114    /**
115     * Setter for the current group
116     */
117    public function set_group($gid)
118    {
119        $this->gid = $gid;
120    }
121
122
123    /**
124     * Save a search string for future listings
125     *
126     * @param mixed Search params to use in listing method, obtained by get_search_set()
127     */
128    public function set_search_set($filter)
129    {
130        $this->filter = $filter;
131    }
132
133
134    /**
135     * Getter for saved search properties
136     *
137     * @return mixed Search properties used by this class
138     */
139    public function get_search_set()
140    {
141        return $this->filter;
142    }
143
144
145    /**
146     * Reset saved results and search parameters
147     */
148    public function reset()
149    {
150        $this->result = null;
151        $this->filter = null;
152    }
153
154
155    /**
156     * List all active contact groups of this source
157     *
158     * @param string  Optional search string to match group name
159     * @return array  Indexed list of contact groups, each a hash array
160     */
161    function list_groups($search = null)
162    {
163        $this->_fetch_groups();
164        $groups = array();
165        foreach ((array)$this->distlists as $group) {
166            if (!$search || strstr(strtolower($group['last-name']), strtolower($search)))
167                $groups[] = array('ID' => $group['ID'], 'name' => $group['last-name']);
168        }
169        return $groups;
170    }
171
172    /**
173     * List the current set of contact records
174     *
175     * @param  array  List of cols to show
176     * @param  int    Only return this number of records, use negative values for tail
177     * @return array  Indexed list of contact records, each a hash array
178     */
179    public function list_records($cols=null, $subset=0)
180    {
181        $this->result = $this->count();
182       
183        // list member of the selected group
184        if ($this->gid) {
185            $seen = array();
186            $this->result->count = 0;
187            foreach ((array)$this->distlists[$this->gid]['member'] as $member) {
188                // skip member that don't match the search filter
189                if ($this->filter && array_search($member['ID'], $this->filter) === false)
190                    continue;
191                if ($this->contacts[$member['ID']] && !$seen[$member['ID']]++)
192                    $this->result->count++;
193            }
194            $ids = array_keys($seen);
195        }
196        else
197            $ids = $this->filter ? $this->filter : array_keys($this->contacts);
198       
199        // fill contact data into the current result set
200        $i = $j = 0;
201        foreach ($ids as $id) {
202            if ($i++ < $this->result->first)
203                continue;
204            $this->result->add($this->contacts[$id]);
205            if (++$j == $this->page_size)
206                break;
207        }
208       
209        return $this->result;
210    }
211
212
213    /**
214     * Search records
215     *
216     * @param array   List of fields to search in
217     * @param string  Search value
218     * @param boolean True if results are requested, False if count only
219     * @param boolean True to skip the count query (select only)
220     * @param array   List of fields that cannot be empty
221     * @return object rcube_result_set List of contact records and 'count' value
222     */
223    public function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array())
224    {
225        $this->_fetch_contacts();
226       
227        // search by ID
228        if ($fields == $this->primary_key) {
229            return $this->get_record($value);
230        }
231
232        $value = strtolower($value);
233        if (!is_array($fields))
234            $fields = array($fields);
235        if (!is_array($required) && !empty($required))
236            $required = array($required);
237       
238        $this->filter = array();
239       
240        // search be iterating over all records in memory
241        foreach ($this->contacts as $id => $contact) {
242            // check if current contact has required values, otherwise skip it
243            if ($required) {
244                foreach ($required as $f)
245                    if (empty($contact[$f]))
246                        continue 2;
247            }
248            foreach ($fields as $f) {
249                foreach ((array)$contact[$f] as $val) {
250                    $val = strtolower($val);
251                    if (($strict && $val == $value) || (!$strict && strstr($val, $value))) {
252                        $this->filter[] = $id;
253                        break 2;
254                    }
255                }
256            }
257        }
258
259        // list records (now limited by $this->filter)
260        return $this->list_records();
261    }
262
263
264    /**
265     * Count number of available contacts in database
266     *
267     * @return rcube_result_set Result set with values for 'count' and 'first'
268     */
269    public function count()
270    {
271        $this->_fetch_contacts();
272        $this->_fetch_groups();
273        $count = $this->gid ? count($this->distlists[$this->gid]['member']) : ($this->filter ? count($this->filter) : count($this->contacts));
274        return new rcube_result_set($count, ($this->list_page-1) * $this->page_size);
275    }
276
277
278    /**
279     * Return the last result set
280     *
281     * @return rcube_result_set Current result set or NULL if nothing selected yet
282     */
283    public function get_result()
284    {
285        return $this->result;
286    }
287
288    /**
289     * Get a specific contact record
290     *
291     * @param mixed record identifier(s)
292     * @param boolean True to return record as associative array, otherwise a result set is returned
293     * @return mixed Result object with all record fields or False if not found
294     */
295    public function get_record($id, $assoc=false)
296    {
297        $this->_fetch_contacts();
298        if ($this->contacts[$id]) {
299            $this->result = new rcube_result_set(1);
300            $this->result->add($this->contacts[$id]);
301            return $assoc ? $this->contacts[$id] : $this->result;
302        }
303
304        return false;
305    }
306
307
308    /**
309     * Get group assignments of a specific contact record
310     *
311     * @param mixed Record identifier
312     * @return array List of assigned groups as ID=>Name pairs
313     */
314    public function get_record_groups($id)
315    {
316        $out = array();
317        $this->_fetch_groups();
318       
319        foreach ((array)$this->groupmembers[$id] as $gid) {
320            if ($group = $this->distlists[$gid])
321                $out[$gid] = $group['last-name'];
322        }
323       
324        return $out;
325    }
326
327
328    /**
329     * Create a new contact record
330     *
331     * @param array Assoziative array with save data
332     *  Keys:   Field name with optional section in the form FIELD:SECTION
333     *  Values: Field value. Can be either a string or an array of strings for multiple values
334     * @param boolean True to check for duplicates first
335     * @return mixed The created record ID on success, False on error
336     */
337    public function insert($save_data, $check=false)
338    {
339        if (!is_array($save_data))
340            return false;
341
342        $insert_id = $existing = false;
343
344        // check for existing records by e-mail comparison
345        if ($check) {
346            foreach ($this->get_col_values('email', $save_data, true) as $email) {
347                if (($res = $this->search('email', $email, true, false)) && $res->count) {
348                    $existing = true;
349                    break;
350                }
351            }
352        }
353       
354        if (!$existing) {
355            // generate new Kolab contact item
356            $object = $this->_from_rcube_contact($save_data);
357            $object['uid'] = $this->contactstorage->generateUID();
358
359            $saved = $this->contactstorage->save($object);
360
361            if (PEAR::isError($saved)) {
362                raise_error(array(
363                  'code' => 600, 'type' => 'php',
364                  'file' => __FILE__, 'line' => __LINE__,
365                  'message' => "Error saving contact object to Kolab server:" . $saved->getMessage()),
366                true, false);
367            }
368            else {
369                $contact = $this->_to_rcube_contact($object);
370                $id = $contact['ID'];
371                $this->contacts[$id] = $contact;
372                $this->id2uid[$id] = $object['uid'];
373                $insert_id = $id;
374            }
375        }
376       
377        return $insert_id;
378    }
379
380
381    /**
382     * Update a specific contact record
383     *
384     * @param mixed Record identifier
385     * @param array Assoziative array with save data
386     *  Keys:   Field name with optional section in the form FIELD:SECTION
387     *  Values: Field value. Can be either a string or an array of strings for multiple values
388     * @return boolean True on success, False on error
389     */
390    public function update($id, $save_data)
391    {
392        $updated = false;
393        $this->_fetch_contacts();
394        if ($this->contacts[$id] && ($uid = $this->id2uid[$id])) {
395            $old = $this->contactstorage->getObject($uid);
396            $object = array_merge($old, $this->_from_rcube_contact($save_data));
397
398            $saved = $this->contactstorage->save($object, $uid);
399            if (PEAR::isError($saved)) {
400                raise_error(array(
401                  'code' => 600, 'type' => 'php',
402                  'file' => __FILE__, 'line' => __LINE__,
403                  'message' => "Error saving contact object to Kolab server:" . $saved->getMessage()),
404                true, false);
405            }
406            else {
407                $this->contacts[$id] = $this->_to_rcube_contact($object);
408                $updated = true;
409            }
410        }
411       
412        return $updated;
413    }
414
415    /**
416     * Mark one or more contact records as deleted
417     *
418     * @param array  Record identifiers
419     */
420    public function delete($ids)
421    {
422        $this->_fetch_contacts();
423        $this->_fetch_groups();
424       
425        if (!is_array($ids))
426            $ids = explode(',', $ids);
427
428        $count = 0;
429        foreach ($ids as $id) {
430            if ($uid = $this->id2uid[$id]) {
431                $deleted = $this->contactstorage->delete($uid);
432
433                if (PEAR::isError($deleted)) {
434                    raise_error(array(
435                      'code' => 600, 'type' => 'php',
436                      'file' => __FILE__, 'line' => __LINE__,
437                      'message' => "Error deleting a contact object from the Kolab server:" . $deleted->getMessage()),
438                    true, false);
439                }
440                else {
441                    // remove from distribution lists
442                    foreach ((array)$this->groupmembers[$id] as $gid)
443                        $this->remove_from_group($gid, $id);
444                   
445                    // clear internal cache
446                    unset($this->contacts[$id], $this->id2uid[$id], $this->groupmembers[$id]);
447                    $count++;
448                }
449            }
450        }
451       
452        return $count;
453    }
454
455    /**
456     * Remove all records from the database
457     */
458    public function delete_all()
459    {
460        if (!PEAR::isError($this->contactstorage->deleteAll())) {
461            $this->contacts = array();
462            $this->id2uid = array();
463            $this->result = null;
464        }
465    }
466
467   
468    /**
469     * Close connection to source
470     * Called on script shutdown
471     */
472    public function close()
473    {
474        rcube_kolab::shutdown();
475    }
476
477
478    /**
479     * Create a contact group with the given name
480     *
481     * @param string The group name
482     * @return mixed False on error, array with record props in success
483     */
484    function create_group($name)
485    {
486        $this->_fetch_groups();
487        $result = false;
488       
489        $list = array(
490            'uid' => $this->liststorage->generateUID(),
491            'last-name' => $name,
492            'member' => array(),
493        );
494        $saved = $this->liststorage->save($list);
495
496        if (PEAR::isError($saved)) {
497            raise_error(array(
498              'code' => 600, 'type' => 'php',
499              'file' => __FILE__, 'line' => __LINE__,
500              'message' => "Error saving distribution-list object to Kolab server:" . $saved->getMessage()),
501            true, false);
502            return false;
503        }
504        else {
505            $id = md5($list['uid']);
506            $this->distlists[$record['ID']] = $list;
507            $result = array('id' => $id, 'name' => $name);
508        }
509
510        return $result;
511    }
512
513    /**
514     * Delete the given group and all linked group members
515     *
516     * @param string Group identifier
517     * @return boolean True on success, false if no data was changed
518     */
519    function delete_group($gid)
520    {
521        $this->_fetch_groups();
522        $result = false;
523       
524        if ($list = $this->distlists[$gid])
525            $deleted = $this->liststorage->delete($list['uid']);
526
527        if (PEAR::isError($deleted)) {
528            raise_error(array(
529              'code' => 600, 'type' => 'php',
530              'file' => __FILE__, 'line' => __LINE__,
531              'message' => "Error deleting distribution-list object from the Kolab server:" . $deleted->getMessage()),
532            true, false);
533        }
534        else
535            $result = true;
536       
537        return $result;
538    }
539
540    /**
541     * Rename a specific contact group
542     *
543     * @param string Group identifier
544     * @param string New name to set for this group
545     * @return boolean New name on success, false if no data was changed
546     */
547    function rename_group($gid, $newname)
548    {
549        $this->_fetch_groups();
550        $list = $this->distlists[$gid];
551       
552        if ($newname != $list['last-name']) {
553            $list['last-name'] = $newname;
554            $saved = $this->liststorage->save($list, $list['uid']);
555        }
556
557        if (PEAR::isError($saved)) {
558            raise_error(array(
559              'code' => 600, 'type' => 'php',
560              'file' => __FILE__, 'line' => __LINE__,
561              'message' => "Error saving distribution-list object to Kolab server:" . $saved->getMessage()),
562            true, false);
563            return false;
564        }
565
566        return $newname;
567    }
568
569    /**
570     * Add the given contact records the a certain group
571     *
572     * @param string  Group identifier
573     * @param array   List of contact identifiers to be added
574     * @return int    Number of contacts added
575     */
576    function add_to_group($gid, $ids)
577    {
578        if (!is_array($ids))
579            $ids = explode(',', $ids);
580
581        $added = 0;
582        $exists = array();
583       
584        $this->_fetch_groups();
585        $this->_fetch_contacts();
586        $list = $this->distlists[$gid];
587
588        foreach ((array)$list['member'] as $i => $member)
589            $exists[] = $member['ID'];
590       
591        // substract existing assignments from list
592        $ids = array_diff($ids, $exists);
593
594        foreach ($ids as $contact_id) {
595            if ($uid = $this->id2uid[$contact_id]) {
596                $contact = $this->contacts[$contact_id];
597                foreach ($this->get_col_values('email', $contact, true) as $email) {
598                    $list['member'][] = array(
599                        'uid' => $uid,
600                        'display-name' => $contact['name'],
601                        'smtp-address' => $email,
602                    );
603                }
604                $this->groupmembers[$contact_id][] = $gid;
605                $added++;
606            }
607        }
608       
609        if ($added)
610            $saved = $this->liststorage->save($list, $list['uid']);
611       
612        if (PEAR::isError($saved)) {
613            raise_error(array(
614              'code' => 600, 'type' => 'php',
615              'file' => __FILE__, 'line' => __LINE__,
616              'message' => "Error saving distribution-list to Kolab server:" . $saved->getMessage()),
617            true, false);
618            $added = false;
619        }
620        else {
621            $this->distlists[$gid] = $list;
622        }
623       
624        return $added;
625    }
626
627    /**
628     * Remove the given contact records from a certain group
629     *
630     * @param string  Group identifier
631     * @param array   List of contact identifiers to be removed
632     * @return int    Number of deleted group members
633     */
634    function remove_from_group($gid, $ids)
635    {
636        if (!is_array($ids))
637            $ids = explode(',', $ids);
638       
639        $this->_fetch_groups();
640        if (!($list = $this->distlists[$gid]))
641            return false;
642
643        $new_member = array();
644        foreach ((array)$list['member'] as $member) {
645            if (!in_array($member['ID'], $ids))
646                $new_member[] = $member;
647        }
648
649        // write distribution list back to server
650        $list['member'] = $new_member;
651        $saved = $this->liststorage->save($list, $list['uid']);
652       
653        if (PEAR::isError($saved)) {
654            raise_error(array(
655              'code' => 600, 'type' => 'php',
656              'file' => __FILE__, 'line' => __LINE__,
657              'message' => "Error saving distribution-list object to Kolab server:" . $saved->getMessage()),
658            true, false);
659        }
660        else {
661            // remove group assigments in local cache
662            foreach ($ids as $id) {
663                $j = array_search($gid, $this->groupmembers[$id]);
664                unset($this->groupmembers[$id][$j]);
665            }
666            $this->distlists[$gid] = $list;
667            return true;
668        }
669
670        return false;
671    }
672
673
674    /**
675     * Simply fetch all records and store them in private member vars
676     */
677    private function _fetch_contacts()
678    {
679        if (!isset($this->contacts)) {
680            // read contacts
681            $this->contacts = $this->id2uid = array();
682            foreach ((array)$this->contactstorage->getObjects() as $record) {
683                $contact = $this->_to_rcube_contact($record);
684                $id = $contact['ID'];
685                $this->contacts[$id] = $contact;
686                $this->id2uid[$id] = $record['uid'];
687            }
688
689            // TODO: sort data arrays according to desired list sorting
690        }
691    }
692   
693   
694    /**
695     * Read distribution-lists AKA groups from server
696     */
697    private function _fetch_groups()
698    {
699        if (!isset($this->distlists)) {
700            $this->distlists = $this->groupmembers = array();
701            foreach ((array)$this->liststorage->getObjects() as $record) {
702                // FIXME: folders without any distribution-list objects return contacts instead ?!
703                if ($record['__type'] != 'Group')
704                    continue;
705                $record['ID'] = md5($record['uid']);
706                foreach ((array)$record['member'] as $i => $member) {
707                    $mid = md5($member['uid']);
708                    $record['member'][$i]['ID'] = $mid;
709                    $this->groupmembers[$mid][] = $record['ID'];
710                }
711                $this->distlists[$record['ID']] = $record;
712            }
713        }
714    }
715   
716   
717    /**
718     * Map fields from internal Kolab_Format to Roundcube contact format
719     */
720    private function _to_rcube_contact($record)
721    {
722        $out = array(
723          'ID' => md5($record['uid']),
724          'email' => array(),
725          'phone' => array(),
726        );
727       
728        foreach ($this->fieldmap as $kolab => $rcube) {
729          if (strlen($record[$kolab]))
730            $out[$rcube] = $record[$kolab];
731        }
732       
733        if (isset($record['gender']))
734            $out['gender'] = $this->gender_map[$record['gender']];
735
736        foreach ((array)$record['email'] as $i => $email)
737            $out['email'][] = $email['smtp-address'];
738           
739        if (!$record['email'] && $record['emails'])
740            $out['email'] = preg_split('/,\s*/', $record['emails']);
741
742        foreach ((array)$record['phone'] as $i => $phone)
743            $out['phone:'.$phone['type']][] = $phone['number'];
744
745        if (is_array($record['address'])) {
746            foreach ($record['address'] as $i => $adr) {
747                $key = 'address:' . $adr['type'];
748                $out[$key][] = array(
749                    'street' => $adr['street'],
750                    'locality' => $adr['locality'],
751                    'zipcode' => $adr['postal-code'],
752                    'region' => $adr['region'],
753                    'country' => $adr['country'],
754                );
755            }
756        }
757
758        // remove empty fields
759        return array_filter($out);
760    }
761
762    private function _from_rcube_contact($contact)
763    {
764        $object = array();
765
766        foreach (array_flip($this->fieldmap) as $rcube => $kolab) {
767            if (isset($contact[$rcube]))
768                $object[$kolab] = is_array($contact[$rcube]) ? $contact[$rcube][0] : $contact[$rcube];
769            else if ($rcube .= ':home' && isset($contact[$rcube]))
770                $object[$kolab] = is_array($contact[$rcube]) ? $contact[$rcube][0] : $contact[$rcube];
771        }
772
773        // format dates
774        if ($object['birthday'] && ($date = @strtotime($object['birthday'])))
775            $object['birthday'] = date('Y-m-d', $date);
776        if ($object['anniversary'] && ($date = @strtotime($object['anniversary'])))
777            $object['anniversary'] = date('Y-m-d', $date);
778
779        $gendermap = array_flip($this->gender_map);
780        if (isset($contact['gender']))
781            $object['gender'] = $gendermap[$contact['gender']];
782
783        $emails = $this->get_col_values('email', $contact, true);
784        $object['emails'] = join(', ', $emails);
785
786        foreach ($this->get_col_values('phone', $contact) as $type => $values) {
787            if ($this->phonetypemap[$type])
788                $type = $this->phonetypemap[$type];
789            foreach ((array)$values as $phone)
790                $object['phone'][] = array('number' => $phone, 'type' => $type);
791        }
792
793        foreach ($this->get_col_values('address', $contact) as $type => $values) {
794            if ($this->addresstypemap[$type])
795                $type = $this->addresstypemap[$type];
796           
797            $basekey = 'addr-' . $type . '-';
798            foreach ((array)$values as $adr) {
799                // switch type if slot is already taken
800                if (isset($object[$basekey . 'type'])) {
801                    $type = $type == 'home' ? 'business' : 'home';
802                    $basekey = 'addr-' . $type . '-';
803                }
804               
805                if (!isset($object[$basekey . 'type'])) {
806                    $object[$basekey . 'type'] = $type;
807                    $object[$basekey . 'street'] = $adr['street'];
808                    $object[$basekey . 'locality'] = $adr['locality'];
809                    $object[$basekey . 'postal-code'] = $adr['zipcode'];
810                    $object[$basekey . 'region'] = $adr['region'];
811                    $object[$basekey . 'country'] = $adr['country'];
812                }
813                else {
814                    $object['address'][] = array(
815                        'type' => $type,
816                        'street' => $adr['street'],
817                        'locality' => $adr['locality'],
818                        'postal-code' => $adr['zipcode'],
819                        'region' => $adr['region'],
820                        'country' => $adr['country'],
821                    );
822                }
823            }
824        }
825
826        return $object;
827    }
828
829}
Note: See TracBrowser for help on using the repository browser.