diff --git a/phpgwapi/inc/class.historylog.inc.php b/phpgwapi/inc/class.historylog.inc.php index bb987170ce..3eadf2f55f 100644 --- a/phpgwapi/inc/class.historylog.inc.php +++ b/phpgwapi/inc/class.historylog.inc.php @@ -1,204 +1,300 @@ * - * Copyright (C) 2001 Joseph Engo * - * -------------------------------------------------------------------------* - * This library is part of the eGroupWare API * - * http://www.egroupware.org/api * - * ------------------------------------------------------------------------ * - * This library is free software; you can redistribute it and/or modify it * - * under the terms of the GNU Lesser General Public License as published by * - * the Free Software Foundation; either version 2.1 of the License, * - * or any later version. * - * This library is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * - * See the GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU Lesser General Public License * - * along with this library; if not, write to the Free Software Foundation, * - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - \**************************************************************************/ +/** + * API - Record history logging + * + * This class extends a backend class (at them moment SQL or LDAP) and implements some + * caching on to top of the backend functions. The cache is share for all instances of + * the accounts class and for LDAP it is persistent through the whole session, for SQL + * it's only on a per request basis. + * + * @link http://www.egroupware.org + * @author Joseph Engo + * @copyright 2001 by Joseph Engo + * @author Ralf Becker new DB-methods and search + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package api + * @subpackage db + * @access public + * @version $Id$ + */ - // $Id$ +/** + * Record history logging service + * + * This class need to be instanciated for EACH app, which wishes to use it! + */ +class historylog +{ + var $db; + var $table = 'egw_history_log'; + /** + * App.name this class is instanciated for / working on + * + * @var string + */ + var $appname; + /** + * offset in secconds between user and server-time, + * it need to be add to a server-time to get the user-time or substracted from a user-time to get the server-time + * + * @var int + */ + var $tz_offset_s; + var $template; + var $nextmatchs; + var $types = array( + 'C' => 'Created', + 'D' => 'Deleted', + 'E' => 'Edited' + ); + var $alternate_handlers = array(); - class historylog + /** + * Constructor + * + * @param string $appname app name this instance operates on + * @return historylog + */ + function historylog($appname='') { - var $db; - var $table = 'egw_history_log'; - var $appname; - var $template; - var $nextmatchs; - var $types = array( - 'C' => 'Created', - 'D' => 'Deleted', - 'E' => 'Edited' - ); - var $alternate_handlers = array(); - - function historylog($appname='') + if (!$appname) { - if (!$appname) - { - $appname = $GLOBALS['egw_info']['flags']['currentapp']; - } - $this->appname = $appname; - - if (is_object($GLOBALS['egw_setup']->db)) - { - $this->db = clone($GLOBALS['egw_setup']->db); - } - else - { - $this->db = clone($GLOBALS['egw']->db); - } - $this->db->set_app('phpgwapi'); + $appname = $GLOBALS['egw_info']['flags']['currentapp']; } - - function delete($record_id) + $this->appname = $appname; + + if (is_object($GLOBALS['egw_setup']->db)) { - if (is_array($record_id) || is_numeric($record_id)) - { - $where = array( - 'history_record_id' => $record_id, - 'history_appname' => $this->appname, - ); - } - else - { - $where = array('history_appname' => $record_id); - } - $this->db->delete($this->table,$where,__LINE__,__FILE__); - - return $this->db->affected_rows(); + $this->db = clone($GLOBALS['egw_setup']->db); } - - function add($status,$record_id,$new_value,$old_value) + else { - if ($new_value != $old_value) - { - $this->db->insert($this->table,array( - 'history_record_id' => $record_id, - 'history_appname' => $this->appname, - 'history_owner' => $GLOBALS['egw_info']['user']['account_id'], - 'history_status' => $status, - 'history_new_value' => $new_value, - 'history_old_value' => $old_value, - 'history_timestamp' => time(), - ),false,__LINE__,__FILE__); - } + $this->db = clone($GLOBALS['egw']->db); } + $this->db->set_app('phpgwapi'); - // array $filter_out - function return_array($filter_out,$only_show,$_orderby = '',$sort = '', $record_id) + if (!is_object($GLOBALS['egw']->datetime)) { - - if (!$_orderby || !preg_match('/^[a-z0-9_]+$/i',$_orderby) || !preg_match('/^(asc|desc)?$/i',$sort)) - { - $orderby = 'ORDER BY history_timestamp,history_id'; - } - else - { - $orderby = "ORDER BY $_orderby $sort"; - } + $GLOBALS['egw']->datetime =& CreateObject('phpgwapi.datetime'); + } + $this->tz_offset_s = $GLOBALS['egw']->datetime->tz_offset; + } - $where = array( - 'history_appname' => $this->appname, + /** + * Delete the history-log of one or multiple records of $this->appname + * + * @param int/array $record_id one or more id's of $this->appname, or null to delete ALL records of $this->appname + * @return int number of deleted records/rows (0 is not necessaryly an error, it can just mean there's no record!) + */ + function delete($record_id) + { + $where = array('history_appname' => $record_id); + + if (is_array($record_id) || is_numeric($record_id)) + { + $where['history_record_id'] = $record_id; + } + $this->db->delete($this->table,$where,__LINE__,__FILE__); + + return $this->db->affected_rows(); + } + + /** + * Add a history record, if $new_value != $old_value + * + * @param string $status 2 letter code: eg. $this->types: C=Created, D=Deleted, E=Edited + * @param int $record_id it of the record in $this->appname (set by the constructor) + * @param string $new_value new value + * @param string $old_value old value + */ + function add($status,$record_id,$new_value,$old_value) + { + if ($new_value != $old_value) + { + $this->db->insert($this->table,array( 'history_record_id' => $record_id, - ); - if (is_array($filter_out)) - { - foreach($filter_out as $_filter) - { - $where[] = 'history_status != '.$this->db->quote($_filter); - } - } - if (is_array($only_show) && count($only_show)) - { - $to_or = array(); - foreach($only_show as $_filter) - { - $to_or[] = 'history_status = '.$this->db->quote($_filter); - } - $where[] = '('.implode(' OR ',$to_or).')'; - } - - $this->db->select($this->table,'*',$where,__LINE__,__FILE__,false,$orderby); - while ($this->db->next_record()) - { - $return_values[] = array( - 'id' => $this->db->f('history_id'), - 'record_id' => $this->db->f('history_record_id'), - 'owner' => $GLOBALS['egw']->accounts->id2name($this->db->f('history_owner')), - 'status' => str_replace(' ','',$this->db->f('history_status')), - 'new_value' => $this->db->f('history_new_value'), - 'old_value' => $this->db->f('history_old_value'), - 'datetime' => $this->db->from_timestamp($this->db->f('history_timestamp')) - ); - } - return $return_values; - } - - function return_html($filter_out,$orderby = '',$sort = '', $record_id) - { - $this->template =& CreateObject('phpgwapi.Template',EGW_TEMPLATE_DIR); - $this->nextmatchs =& CreateObject('phpgwapi.nextmatchs'); - - $this->template->set_file('_history','history_list.tpl'); - - $this->template->set_block('_history','row_no_history'); - $this->template->set_block('_history','list'); - $this->template->set_block('_history','row'); - - $this->template->set_var('lang_user',lang('User')); - $this->template->set_var('lang_date',lang('Date')); - $this->template->set_var('lang_action',lang('Action')); - $this->template->set_var('lang_new_value',lang('New Value')); - - $this->template->set_var('th_bg',$GLOBALS['egw_info']['theme']['th_bg']); - $this->template->set_var('sort_date',lang('Date')); - $this->template->set_var('sort_owner',lang('User')); - $this->template->set_var('sort_status',lang('Status')); - $this->template->set_var('sort_new_value',lang('New value')); - $this->template->set_var('sort_old_value',lang('Old value')); - - $values = $this->return_array($filter_out,array(),$orderby,$sort,$record_id); - - if (!is_array($values)) - { - $this->template->set_var('tr_color',$GLOBALS['egw_info']['theme']['row_off']); - $this->template->set_var('lang_no_history',lang('No history for this record')); - $this->template->fp('rows','row_no_history'); - return $this->template->fp('out','list'); - } - - foreach($values as $value) - { - $this->nextmatchs->template_alternate_row_color($this->template); - - $this->template->set_var('row_date',$GLOBALS['egw']->common->show_date($value['datetime'])); - $this->template->set_var('row_owner',$value['owner']); - - if ($this->alternate_handlers[$value['status']]) - { - eval('\$s = ' . $this->alternate_handlers[$value['status']] . '(' . $value['new_value'] . ');'); - $this->template->set_var('row_new_value',$s); - unset($s); - - eval('\$s = ' . $this->alternate_handlers[$value['status']] . '(' . $value['old_value'] . ');'); - $this->template->set_var('row_old_value',$s); - unset($s); - } - else - { - $this->template->set_var('row_new_value',$value['new_value']); - $this->template->set_var('row_old_value',$value['old_value']); - } - - $this->template->set_var('row_status',$this->types[$value['status']]); - - $this->template->fp('rows','row',True); - } - return $this->template->fp('out','list'); + 'history_appname' => $this->appname, + 'history_owner' => $GLOBALS['egw_info']['user']['account_id'], + 'history_status' => $status, + 'history_new_value' => $new_value, + 'history_old_value' => $old_value, + 'history_timestamp' => time(), + ),false,__LINE__,__FILE__); } } + + /** + * Search history-log + * + * @param array/int $filter array with filters, or int record_id + * @param string $order='history_id' sorting after history_id is identical to history_timestamp + * @param string $sort='ASC' + * @return array of arrays with keys id, record_id, appname, owner (account_id), status, new_value, old_value, + * timestamp (Y-m-d H:i:s in servertime), user_ts (timestamp in user-time) + */ + function search($filter,$order='history_id',$sort='DESC') + { + if (!is_array($filter)) $filter = (int)$filter ? array('history_record_id' => $filter) : array(); + + if (!$_orderby || !preg_match('/^[a-z0-9_]+$/i',$_orderby) || !preg_match('/^(asc|desc)?$/i',$sort)) + { + $orderby = 'ORDER BY history_id DESC'; + } + else + { + $orderby = "ORDER BY $_orderby $sort"; + } + foreach($filter as $col => $value) + { + if (substr($col,0,8) != 'history_') + { + $filter['history_'.$col] = $value; + unset($filter[$col]); + } + } + if (!isset($filter['history_appname'])) $filter['history_appname'] = $this->appname; + + $this->db->select($this->table,'*',$filter,__LINE__,__FILE__,false,$orderby); + $rows = array(); + while(($row = $this->db->row(true,'history_'))) + { + $row['user_ts'] = $this->db->from_timestamp($row['timestamp']) + 3600 * $GLOBALS['egw_info']['user']['preferences']['common']['tz_offset']; + $rows[] = $row; + } + return $rows; + } + + /** + * return history-log for one record of $this->appname + * + * @deprecated use search + * @param array $filter_out stati to NOT show + * @param array $only_show stati to show + * @param string $_orderby column name to order, default history_timestamp,history_id + * @param string $sort ASC,DESC + * @param int $record_id id of the record in $this->appname (set by the constructor) + * @return array of arrays with keys id, record_id, owner (account_lid!), status, new_value, old_value, datetime (timestamp in servertime) + */ + function return_array($filter_out,$only_show,$_orderby,$sort, $record_id) + { + + if (!$_orderby || !preg_match('/^[a-z0-9_]+$/i',$_orderby) || !preg_match('/^(asc|desc)?$/i',$sort)) + { + $orderby = 'ORDER BY history_timestamp,history_id'; + } + else + { + $orderby = "ORDER BY $_orderby $sort"; + } + + $where = array( + 'history_appname' => $this->appname, + 'history_record_id' => $record_id, + ); + if (is_array($filter_out)) + { + foreach($filter_out as $_filter) + { + $where[] = 'history_status != '.$this->db->quote($_filter); + } + } + if (is_array($only_show) && count($only_show)) + { + $to_or = array(); + foreach($only_show as $_filter) + { + $to_or[] = 'history_status = '.$this->db->quote($_filter); + } + $where[] = '('.implode(' OR ',$to_or).')'; + } + + $this->db->select($this->table,'*',$where,__LINE__,__FILE__,false,$orderby); + while ($this->db->next_record()) + { + $return_values[] = array( + 'id' => $this->db->f('history_id'), + 'record_id' => $this->db->f('history_record_id'), + 'owner' => $GLOBALS['egw']->accounts->id2name($this->db->f('history_owner')), + 'status' => str_replace(' ','',$this->db->f('history_status')), + 'new_value' => $this->db->f('history_new_value'), + 'old_value' => $this->db->f('history_old_value'), + 'datetime' => $this->db->from_timestamp($this->db->f('history_timestamp')) + ); + } + return $return_values; + } + + /** + * Creates html to show the history-log of one record + * + * @deprecated use eg. the historylog_widget of eTemplate or your own UI + * @param array $filter_out see stati to NOT show + * @param string $orderby column-name to order by + * @param string $sort ASC, DESC + * @param int $record_id id of the record in $this->appname (set by the constructor) + * @return string the html + */ + function return_html($filter_out,$orderby,$sort, $record_id) + { + $this->template =& CreateObject('phpgwapi.Template',EGW_TEMPLATE_DIR); + $this->nextmatchs =& CreateObject('phpgwapi.nextmatchs'); + + $this->template->set_file('_history','history_list.tpl'); + + $this->template->set_block('_history','row_no_history'); + $this->template->set_block('_history','list'); + $this->template->set_block('_history','row'); + + $this->template->set_var('lang_user',lang('User')); + $this->template->set_var('lang_date',lang('Date')); + $this->template->set_var('lang_action',lang('Action')); + $this->template->set_var('lang_new_value',lang('New Value')); + + $this->template->set_var('th_bg',$GLOBALS['egw_info']['theme']['th_bg']); + $this->template->set_var('sort_date',lang('Date')); + $this->template->set_var('sort_owner',lang('User')); + $this->template->set_var('sort_status',lang('Status')); + $this->template->set_var('sort_new_value',lang('New value')); + $this->template->set_var('sort_old_value',lang('Old value')); + + $values = $this->return_array($filter_out,array(),$orderby,$sort,$record_id); + + if (!is_array($values)) + { + $this->template->set_var('tr_color',$GLOBALS['egw_info']['theme']['row_off']); + $this->template->set_var('lang_no_history',lang('No history for this record')); + $this->template->fp('rows','row_no_history'); + return $this->template->fp('out','list'); + } + + foreach($values as $value) + { + $this->nextmatchs->template_alternate_row_color($this->template); + + $this->template->set_var('row_date',$GLOBALS['egw']->common->show_date($value['datetime'])); + $this->template->set_var('row_owner',$value['owner']); + + if ($this->alternate_handlers[$value['status']]) + { + eval('\$s = ' . $this->alternate_handlers[$value['status']] . '(' . $value['new_value'] . ');'); + $this->template->set_var('row_new_value',$s); + unset($s); + + eval('\$s = ' . $this->alternate_handlers[$value['status']] . '(' . $value['old_value'] . ');'); + $this->template->set_var('row_old_value',$s); + unset($s); + } + else + { + $this->template->set_var('row_new_value',$value['new_value']); + $this->template->set_var('row_old_value',$value['old_value']); + } + + $this->template->set_var('row_status',$this->types[$value['status']]); + + $this->template->fp('rows','row',True); + } + return $this->template->fp('out','list'); + } +}