2005-11-04 00:47:52 +01:00
|
|
|
<?php
|
|
|
|
/**************************************************************************\
|
|
|
|
* eGroupWare - Adressbook - General storage object *
|
|
|
|
* http://www.egroupware.org *
|
|
|
|
* Written and (c) 2005 by Cornelius_weiss <egw@von-und-zu-weiss.de> *
|
|
|
|
* -------------------------------------------- *
|
|
|
|
* This program is free software; you can redistribute it and/or modify it *
|
|
|
|
* under the terms of the GNU General Public License as published by the *
|
|
|
|
* Free Software Foundation; either version 2 of the License, or (at your *
|
|
|
|
* option) any later version. *
|
|
|
|
\**************************************************************************/
|
|
|
|
|
|
|
|
/* $Id$ */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* General storage object of the adressbook
|
|
|
|
*
|
2005-11-10 13:22:55 +01:00
|
|
|
* @package addressbook
|
2005-11-04 00:47:52 +01:00
|
|
|
* @author Cornelius Weiss <egw@von-und-zu-weiss.de>
|
|
|
|
* @copyright (c) 2005 by Cornelius Weiss <egw@von-und-zu-weiss.de>
|
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
|
|
|
|
*/
|
|
|
|
|
|
|
|
class socontacts
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* @var string $links_table table name 'egw_links'
|
|
|
|
*/
|
|
|
|
var $links_table = 'egw_links';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string $extra_table name of customefields table
|
|
|
|
*/
|
2005-11-13 13:05:35 +01:00
|
|
|
var $extra_table = 'egw_addressbook_extra';
|
2005-11-04 00:47:52 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string $extra_id
|
|
|
|
*/
|
|
|
|
var $extra_id = 'contact_id';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string $extra_owner
|
|
|
|
*/
|
|
|
|
var $extra_owner = 'contact_owner';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string $extra_key
|
|
|
|
*/
|
|
|
|
var $extra_key = 'contact_name';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string $extra_value
|
|
|
|
*/
|
|
|
|
var $extra_value = 'contact_value';
|
|
|
|
|
|
|
|
function socontacts($contact_app='addressbook')
|
|
|
|
{
|
|
|
|
if($GLOBALS['egw_info']['server']['contact_repository'] == 'sql' || !isset($GLOBALS['egw_info']['server']['contact_repository']))
|
|
|
|
{
|
2005-11-13 13:05:35 +01:00
|
|
|
$this->somain =& CreateObject('etemplate.so_sql','phpgwapi','egw_addressbook');
|
2005-11-04 00:47:52 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-11-07 17:12:41 +01:00
|
|
|
$this->somain =& CreateObject('addressbook.so_'.$GLOBALS['egw_info']['server']['contact_repository']);
|
2005-11-04 00:47:52 +01:00
|
|
|
}
|
|
|
|
$this->somain->contacts_id = 'id';
|
2005-11-07 17:12:41 +01:00
|
|
|
$this->soextra =& CreateObject('etemplate.so_sql');
|
2005-11-04 00:47:52 +01:00
|
|
|
$this->soextra->so_sql('phpgwapi',$this->extra_table);
|
|
|
|
|
|
|
|
$custom =& CreateObject('admin.customfields',$contact_app);
|
|
|
|
$this->customfields = $custom->get_customfields();
|
2005-11-07 17:12:41 +01:00
|
|
|
if ($this->customfields && !is_array($this->customfields))
|
|
|
|
{
|
|
|
|
$this->customfields = unserialize($this->customfields);
|
|
|
|
}
|
|
|
|
if (!$this->customfields) $this->customfields = array();
|
2005-11-04 00:47:52 +01:00
|
|
|
}
|
|
|
|
|
2006-03-07 23:43:08 +01:00
|
|
|
/**
|
|
|
|
* changes the data from the db-format to your work-format
|
|
|
|
*
|
|
|
|
* it gets called everytime when data is read from the db
|
|
|
|
* This function needs to be reimplemented in the derived class
|
|
|
|
*
|
|
|
|
* @param array $data
|
|
|
|
*/
|
|
|
|
function db2data($data)
|
|
|
|
{
|
|
|
|
// do the necessare changes here
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* changes the data from your work-format to the db-format
|
|
|
|
*
|
|
|
|
* It gets called everytime when data gets writen into db or on keys for db-searches
|
|
|
|
* this needs to be reimplemented in the derived class
|
|
|
|
*
|
|
|
|
* @param array $data
|
|
|
|
*/
|
|
|
|
function data2db($data)
|
|
|
|
{
|
|
|
|
// do the necessary changes here
|
|
|
|
|
|
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
2005-11-04 00:47:52 +01:00
|
|
|
/**
|
|
|
|
* deletes contact entry including custom fields
|
|
|
|
*
|
|
|
|
* @param array &$contact contact data from etemplate::exec
|
|
|
|
* @return bool false if all went right
|
|
|
|
*/
|
|
|
|
function delete(&$contact)
|
|
|
|
{
|
|
|
|
// delete mainfields
|
|
|
|
$ok_main = $this->somain->delete(array('id' => $contact['id']));
|
|
|
|
|
|
|
|
// delete customfields
|
|
|
|
$ok_extra = $this->soextra->delete(array($this->extra_id => $contact['id']));
|
|
|
|
return !((bool)$ok_extra & (bool)$ok);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* saves contact data including custiom felds
|
|
|
|
*
|
|
|
|
* @param array &$contact contact data from etemplate::exec
|
|
|
|
* @return bool false if all went wrong, errornumber on failure
|
|
|
|
*/
|
|
|
|
function save(&$contact)
|
|
|
|
{
|
|
|
|
// save mainfields
|
2006-03-07 23:43:08 +01:00
|
|
|
$this->somain->data = $this->data2db($contact);
|
2005-11-04 00:47:52 +01:00
|
|
|
$error_nr = $this->somain->save();
|
|
|
|
$contact['id'] = $this->somain->data['id'];
|
|
|
|
if($error_nr) return $error_nr_main;
|
2005-11-07 17:12:41 +01:00
|
|
|
|
2005-11-04 00:47:52 +01:00
|
|
|
// save customfields
|
2006-02-16 12:50:16 +01:00
|
|
|
foreach ((array)$this->customfields + array('ophone' => '', 'address2' => '' , 'address3' => '') as $field => $options)
|
2005-11-04 00:47:52 +01:00
|
|
|
{
|
|
|
|
$value = $contact['#'.$field];
|
|
|
|
$data = array(
|
|
|
|
$this->extra_id => $contact['id'],
|
|
|
|
$this->extra_owner => $contact['owner'],
|
|
|
|
$this->extra_key => $field,
|
|
|
|
$this->extra_value => $value,
|
|
|
|
);
|
|
|
|
$this->soextra->data = $data;
|
|
|
|
$error_nr = $this->soextra->save();
|
|
|
|
if($error_nr) return $error_nr;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* reads contact data including custom fields
|
|
|
|
*
|
|
|
|
* @param interger $contact_id contact_id
|
|
|
|
* @return array/boolean data if row could be retrived else False
|
|
|
|
*/
|
|
|
|
function read($contact_id)
|
|
|
|
{
|
|
|
|
// read main data
|
2006-03-07 23:43:08 +01:00
|
|
|
if (!($contact = $this->somain->read($contact_id)))
|
|
|
|
{
|
|
|
|
return $contact;
|
|
|
|
}
|
2005-11-04 00:47:52 +01:00
|
|
|
|
|
|
|
// read customfilds
|
|
|
|
$keys = array(
|
|
|
|
$this->extra_id => $contact['id'],
|
|
|
|
$this->extra_owner => $contact['owner'],
|
|
|
|
);
|
|
|
|
$customfields = $this->soextra->search($keys,false);
|
|
|
|
foreach ((array)$customfields as $field)
|
|
|
|
{
|
|
|
|
$contact['#'.$field[$this->extra_key]] = $field[$this->extra_value];
|
|
|
|
}
|
2006-03-07 23:43:08 +01:00
|
|
|
return $this->db2data($contact);
|
2005-11-04 00:47:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* searches db for rows matching searchcriteria
|
|
|
|
*
|
|
|
|
* '*' and '?' are replaced with sql-wildcards '%' and '_'
|
|
|
|
*
|
|
|
|
* @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!)
|
|
|
|
* @param boolean/string $only_keys=true True returns only keys, False returns all cols. comma seperated list of keys to return
|
|
|
|
* @param string $order_by='' fieldnames + {ASC|DESC} separated by colons ',', can also contain a GROUP BY (if it contains ORDER BY)
|
|
|
|
* @param string/array $extra_cols='' string or array of strings to be added to the SELECT, eg. "count(*) as num"
|
|
|
|
* @param string $wildcard='' appended befor and after each criteria
|
|
|
|
* @param boolean $empty=false False=empty criteria are ignored in query, True=empty have to be empty in row
|
|
|
|
* @param string $op='AND' defaults to 'AND', can be set to 'OR' too, then criteria's are OR'ed together
|
|
|
|
* @param mixed $start=false if != false, return only maxmatch rows begining with start, or array($start,$num)
|
|
|
|
* @param array $filter=null if set (!=null) col-data pairs, to be and-ed (!) into the query without wildcards
|
|
|
|
* @param string $join='' sql to do a join, added as is after the table-name, eg. ", table2 WHERE x=y" or
|
|
|
|
* "LEFT JOIN table2 ON (x=y)", Note: there's no quoting done on $join!
|
|
|
|
* @param boolean $need_full_no_count=false If true an unlimited query is run to determine the total number of rows, default false
|
|
|
|
* @return array of matching rows (the row is an array of the cols) or False
|
|
|
|
*/
|
|
|
|
function search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false)
|
|
|
|
{
|
2005-12-30 13:47:24 +01:00
|
|
|
//echo 'socontacts::search->criteria:'; _debug_array($criteria);
|
2005-11-04 00:47:52 +01:00
|
|
|
// We just want to deal with generalized vars, to simpyfie porting of this code to so_sql later...
|
|
|
|
$this->main_id = $this->somain->contacts_id;
|
2005-11-10 13:22:55 +01:00
|
|
|
|
2005-11-04 00:47:52 +01:00
|
|
|
// seperate custom fields from main fields
|
|
|
|
foreach ($criteria as $crit_key => $crit_val)
|
|
|
|
{
|
|
|
|
if(!(isset($this->somain->db_data_cols [$crit_key]) || isset($this->somain->db_key_cols [$crit_key])))
|
|
|
|
{
|
2005-11-10 13:22:55 +01:00
|
|
|
if(strpos($crit_key,'#') !== false && $crit_key{0} != '!' )
|
2005-11-04 00:47:52 +01:00
|
|
|
{
|
|
|
|
$extra_crit_key = substr($crit_key,1);
|
|
|
|
$criteria_extra[$extra_crit_key][$this->extra_key] = $extra_crit_key;
|
2005-11-08 00:06:16 +01:00
|
|
|
$criteria_extra[$extra_crit_key][$this->extra_value] = $crit_val;
|
2005-11-04 00:47:52 +01:00
|
|
|
}
|
|
|
|
unset($criteria[$crit_key]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//_debug_array($criteria);
|
|
|
|
//_debug_array($criteria_extra);
|
|
|
|
|
|
|
|
// search in custom fields
|
|
|
|
$resultextra = array();
|
|
|
|
if (count($criteria_extra) >= 1)
|
|
|
|
{
|
|
|
|
$firstrun = true;
|
|
|
|
foreach ((array)$criteria_extra as $extra_crit)
|
|
|
|
{
|
2005-11-10 14:29:05 +01:00
|
|
|
if($extra_crit[$this->extra_value]{0} == '!')
|
|
|
|
{
|
|
|
|
if(!isset($all_main_ids)) $all_main_ids = $this->somain->search(array($this->main_id => '*'));
|
|
|
|
$extra_crit[$this->extra_value] = substr($extra_crit[$this->extra_value],1);
|
|
|
|
$not_result = $this->soextra->search($extra_crit,true,'','',$wildcard);
|
|
|
|
if(is_array($not_result))
|
|
|
|
{
|
|
|
|
$expr = '$not_result[0]';
|
|
|
|
for($i=1; $i<count($not_result); $i++)
|
|
|
|
{
|
|
|
|
$expr .= ',$not_result['.$i.']';
|
|
|
|
}
|
2005-11-14 17:44:23 +01:00
|
|
|
@eval('$not_result = array_merge_recursive('.$expr.');');
|
2005-11-10 14:29:05 +01:00
|
|
|
}
|
|
|
|
foreach($all_main_ids as $entry)
|
|
|
|
{
|
|
|
|
if(array_search($entry[$this->main_id],(array)$not_result[$this->extra_id]) === false)
|
|
|
|
{
|
|
|
|
$result[] = array(
|
|
|
|
$this->extra_id => $entry[$this->main_id],
|
|
|
|
$this->extra_key => $extra_crit[$this->extra_key],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$result = $this->soextra->search($extra_crit,true,'','',$wildcard);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($op == 'OR' && $result)
|
2005-11-04 00:47:52 +01:00
|
|
|
{
|
|
|
|
$resultextra = array_merge_recursive((array)$result,(array)$resultextra);
|
|
|
|
}
|
|
|
|
elseif ($op == 'AND')
|
|
|
|
{
|
2005-11-10 14:29:05 +01:00
|
|
|
if (!$result)
|
2005-11-04 00:47:52 +01:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
//$resultextra = array();
|
|
|
|
//break;
|
|
|
|
}
|
|
|
|
$expr = '$result[0]';
|
|
|
|
for($i=1; $i<count($result); $i++)
|
|
|
|
{
|
|
|
|
$expr .= ',$result['.$i.']';
|
|
|
|
}
|
2005-11-14 17:44:23 +01:00
|
|
|
@eval('$merge = array_merge_recursive('.$expr.');');
|
2005-11-04 00:47:52 +01:00
|
|
|
if(!is_array($merge[$this->extra_id]))
|
|
|
|
{
|
|
|
|
$merge[$this->extra_id] = (array)$merge[$this->extra_id];
|
|
|
|
}
|
|
|
|
if($firstrun)
|
|
|
|
{
|
|
|
|
$resultextra = $merge[$this->extra_id];
|
|
|
|
$firstrun = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$resultextra = array_intersect((array)$resultextra,$merge[$this->extra_id]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if($op == 'OR' && $resultextra)
|
|
|
|
{
|
|
|
|
$expr = '$resultextra[0]';
|
|
|
|
for($i=1; $i<count($resultextra); $i++)
|
|
|
|
{
|
|
|
|
$expr .= ',$resultextra['.$i.']';
|
|
|
|
}
|
2005-11-14 17:44:23 +01:00
|
|
|
@eval('$merge = array_merge_recursive('.$expr.');');
|
2005-11-08 00:06:16 +01:00
|
|
|
$resultextra = array_unique((array)$merge[$this->extra_id]);
|
2005-11-04 00:47:52 +01:00
|
|
|
}
|
|
|
|
}
|
2005-12-30 13:47:24 +01:00
|
|
|
//echo 'socontacts::search->resultextra:'; _debug_array($resultextra);
|
2005-11-04 00:47:52 +01:00
|
|
|
|
|
|
|
// search in main fields
|
|
|
|
$result = array();
|
|
|
|
// include results from extrafieldsearch
|
|
|
|
if(!empty($resultextra))
|
|
|
|
{
|
|
|
|
$criteria[$this->main_id] = $resultextra;
|
|
|
|
}
|
|
|
|
if (count($criteria) >= 1)
|
|
|
|
{
|
2005-12-30 13:47:24 +01:00
|
|
|
// We do have to apply wildcard by hand, as the result-ids of extrasearch are included in this search
|
|
|
|
if($wildcard)
|
|
|
|
{
|
|
|
|
foreach ($criteria as $field => $value)
|
|
|
|
{
|
|
|
|
if ($field == $this->main_id) continue;
|
|
|
|
$criteria[$field] = '*'.$value.'*';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$result = $this->somain->search($criteria,true,$order_by,$extra_cols,false,$empty,$op,false,$filter);
|
2005-11-04 00:47:52 +01:00
|
|
|
if(!is_array($result)) return false;
|
|
|
|
$expr = '$result[0]';
|
|
|
|
for($i=1; $i<count($result); $i++)
|
|
|
|
{
|
|
|
|
$expr .= ',$result['.$i.']';
|
|
|
|
}
|
2005-11-14 17:44:23 +01:00
|
|
|
@eval('$merge = array_merge_recursive('.$expr.');');
|
2005-11-04 00:47:52 +01:00
|
|
|
$result = ($merge[$this->main_id]);
|
|
|
|
}
|
2005-12-30 13:47:24 +01:00
|
|
|
//echo 'socontacts::search->result:'; _debug_array($result);
|
2005-11-04 00:47:52 +01:00
|
|
|
|
|
|
|
if(count($result) == 0) return false;
|
|
|
|
if(!is_bool($only_keys_main = $only_keys))
|
|
|
|
{
|
|
|
|
$keys_wanted = explode(',',$only_keys);
|
|
|
|
foreach ($keys_wanted as $num => $key_wanted)
|
|
|
|
{
|
|
|
|
if(!(isset($this->somain->db_data_cols [$key_wanted]) || isset($this->somain->db_key_cols [$key_wanted])))
|
|
|
|
{
|
|
|
|
unset($keys_wanted[$num]);
|
|
|
|
$keys_wanted_custom[] = $key_wanted;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$only_keys_main = implode(',',$keys_wanted);
|
|
|
|
}
|
|
|
|
$result = $this->somain->search(array($this->main_id => $result),$only_keys_main,$order_by,$extra_cols,'','','OR',$start,$filter,$join,$need_full_no_count);
|
|
|
|
|
|
|
|
// append custom fields for each row
|
|
|
|
if($only_keys === false || is_array($keys_wanted_custom))
|
|
|
|
{
|
|
|
|
foreach ($result as $num => $contact)
|
|
|
|
{
|
|
|
|
$extras = $this->soextra->search(array($this->extra_id => $contact[$this->main_id]),false);
|
|
|
|
foreach ((array)$extras as $extra)
|
|
|
|
{
|
|
|
|
if ($only_keys === false || in_array($extra[$this->extra_key],$keys_wanted_custom))
|
|
|
|
{
|
|
|
|
$result[$num][$extra[$this->extra_key]] = $extra[$this->extra_value];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-03-07 23:43:08 +01:00
|
|
|
foreach($result as $num => $contact)
|
|
|
|
{
|
|
|
|
$result[$num] = $this->db2data($contact);
|
|
|
|
}
|
2005-11-04 00:47:52 +01:00
|
|
|
return $need_full_no_count ? count($result) : $result;
|
|
|
|
}
|
2005-12-01 18:21:38 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* gets all contact fields from database
|
|
|
|
*/
|
|
|
|
function get_contact_conlumns()
|
|
|
|
{
|
|
|
|
$fields = $this->somain->db_data_cols;
|
|
|
|
foreach ((array)$this->customfields as $cfield => $coptions)
|
|
|
|
{
|
|
|
|
$fields['#'.$cfield] = '#'.$cfield;
|
|
|
|
}
|
|
|
|
return $fields;
|
|
|
|
}
|
2005-11-04 00:47:52 +01:00
|
|
|
}
|