2004-11-07 15:38:00 +01:00
< ? php
2007-03-09 12:39:47 +01:00
/**
* eGroupWare - Calendar ' s storage - object
*
* @ link http :// www . egroupware . org
* @ package calendar
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de >
2009-11-04 08:57:55 +01:00
* @ author Christian Binder < christian - AT - jaytraxx . de >
2009-07-15 22:35:56 +02:00
* @ author Joerg Lehrke < jlehrke @ noc . de >
2010-07-02 08:00:25 +02:00
* @ copyright ( c ) 2005 - 10 by RalfBecker - At - outdoor - training . de
2007-03-09 12:39:47 +01:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ version $Id $
*/
2004-11-07 15:38:00 +01:00
/**
2005-11-09 00:15:14 +01:00
* some necessary defines used by the calendar
*/
2009-08-04 19:14:16 +02:00
if ( ! extension_loaded ( 'mcal' ))
2005-11-09 00:15:14 +01:00
{
define ( 'MCAL_RECUR_NONE' , 0 );
define ( 'MCAL_RECUR_DAILY' , 1 );
define ( 'MCAL_RECUR_WEEKLY' , 2 );
define ( 'MCAL_RECUR_MONTHLY_MDAY' , 3 );
define ( 'MCAL_RECUR_MONTHLY_WDAY' , 4 );
define ( 'MCAL_RECUR_YEARLY' , 5 );
define ( 'MCAL_RECUR_SECONDLY' , 6 );
define ( 'MCAL_RECUR_MINUTELY' , 7 );
define ( 'MCAL_RECUR_HOURLY' , 8 );
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
define ( 'MCAL_M_SUNDAY' , 1 );
define ( 'MCAL_M_MONDAY' , 2 );
define ( 'MCAL_M_TUESDAY' , 4 );
define ( 'MCAL_M_WEDNESDAY' , 8 );
define ( 'MCAL_M_THURSDAY' , 16 );
define ( 'MCAL_M_FRIDAY' , 32 );
define ( 'MCAL_M_SATURDAY' , 64 );
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
define ( 'MCAL_M_WEEKDAYS' , 62 );
define ( 'MCAL_M_WEEKEND' , 65 );
define ( 'MCAL_M_ALLDAYS' , 127 );
}
define ( 'REJECTED' , 0 );
define ( 'NO_RESPONSE' , 1 );
define ( 'TENTATIVE' , 2 );
define ( 'ACCEPTED' , 3 );
2010-02-17 14:29:28 +01:00
define ( 'DELEGATED' , 4 );
2005-11-09 00:15:14 +01:00
2009-08-10 11:24:39 +02:00
define ( 'HOUR_s' , 60 * 60 );
define ( 'DAY_s' , 24 * HOUR_s );
define ( 'WEEK_s' , 7 * DAY_s );
2005-11-09 00:15:14 +01:00
/**
* Class to store all calendar data ( storage object )
2004-11-07 15:38:00 +01:00
*
2005-11-09 00:15:14 +01:00
* Tables used by socal :
* - egw_cal : general calendar data : cal_id , title , describtion , locations , ...
* - egw_cal_dates : start - and enddates ( multiple entry per cal_id for recuring events ! )
2007-10-09 10:50:06 +02:00
* - egw_cal_user : participant info including status ( multiple entries per cal_id AND startdate for recuring events )
2005-11-09 00:15:14 +01:00
* - egw_cal_repeats : recur - data : type , optional enddate , etc .
* - egw_cal_extra : custom fields ( multiple entries per cal_id possible )
2006-03-29 09:01:18 +02:00
*
2004-11-07 15:38:00 +01:00
* The new UI , BO and SO classes have a strikt definition , in which time - zone they operate :
* UI only operates in user - time , so there have to be no conversation at all !!!
* BO ' s functions take and return user - time only ( ! ), they convert internaly everything to servertime , because
2005-11-09 00:15:14 +01:00
* SO operates only on server - time
2004-11-07 15:38:00 +01:00
*/
2008-06-07 19:45:33 +02:00
class calendar_so
2004-11-07 15:38:00 +01:00
{
/**
* name of the main calendar table and prefix for all other calendar tables
*/
2005-11-09 00:15:14 +01:00
var $cal_table = 'egw_cal' ;
var $extra_table , $repeats_table , $user_table , $dates_table , $all_tables ;
2006-03-29 09:01:18 +02:00
2004-11-07 15:38:00 +01:00
/**
2009-05-06 11:11:37 +02:00
* reference to global db - object
2008-05-08 00:12:25 +02:00
*
2007-05-07 10:27:50 +02:00
* @ var egw_db
2004-11-07 15:38:00 +01:00
*/
var $db ;
2007-05-07 10:27:50 +02:00
/**
* instance of the async object
*
* @ var asyncservice
*/
var $async ;
2008-07-18 13:36:09 +02:00
/**
* SQL to sort by status U , T , A , R
*
*/
const STATUS_SORT = " CASE cal_status WHEN 'U' THEN 1 WHEN 'T' THEN 2 WHEN 'A' THEN 3 WHEN 'R' THEN 4 ELSE 0 END ASC " ;
2005-11-09 00:15:14 +01:00
2009-11-19 11:13:17 +01:00
/**
* Cached timezone data
*
* @ var array id => data
*/
protected static $tz_cache = array ();
2004-11-07 15:38:00 +01:00
/**
* Constructor of the socal class
*/
2008-06-07 19:45:33 +02:00
function __construct ()
2004-11-07 15:38:00 +01:00
{
2008-03-21 21:30:19 +01:00
$this -> async = $GLOBALS [ 'egw' ] -> asyncservice ;
2008-03-15 15:10:20 +01:00
$this -> db = $GLOBALS [ 'egw' ] -> db ;
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
$this -> all_tables = array ( $this -> cal_table );
foreach ( array ( 'extra' , 'repeats' , 'user' , 'dates' ) as $name )
2004-11-07 15:38:00 +01:00
{
$vname = $name . '_table' ;
2005-11-09 00:15:14 +01:00
$this -> all_tables [] = $this -> $vname = $this -> cal_table . '_' . $name ;
2004-11-07 15:38:00 +01:00
}
}
2006-03-29 09:01:18 +02:00
2004-11-07 15:38:00 +01:00
/**
* reads one or more calendar entries
*
* All times ( start , end and modified ) are returned as timesstamps in servertime !
*
2009-07-15 22:35:56 +02:00
* @ param int | array | string $ids id or array of id ' s of the entries to read , or string with a single uid
2010-01-15 09:49:36 +01:00
* @ param int $recur_date = 0 if set read the next recurrence at or after the timestamp , default 0 = read the initital one
2009-05-05 00:39:27 +02:00
* @ return array | boolean array with id => data pairs or false if entry not found
2004-11-07 15:38:00 +01:00
*/
2005-11-09 00:15:14 +01:00
function read ( $ids , $recur_date = 0 )
2004-11-07 15:38:00 +01:00
{
2009-08-06 13:29:05 +02:00
if ( isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ]))
{
2009-07-15 22:35:56 +02:00
$minimum_uid_length = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ];
2009-08-06 13:29:05 +02:00
}
else
{
2009-07-15 22:35:56 +02:00
$minimum_uid_length = 8 ;
}
2005-11-09 00:15:14 +01:00
//echo "<p>socal::read(".print_r($ids,true).",$recur_date)<br />\n".function_backtrace()."<p>\n";
$table_def = $this -> db -> get_table_definitions ( 'calendar' , $this -> cal_table );
$group_by_cols = $this -> cal_table . '.' . implode ( ',' . $this -> cal_table . '.' , array_keys ( $table_def [ 'fd' ]));
$table_def = $this -> db -> get_table_definitions ( 'calendar' , $this -> repeats_table );
$group_by_cols .= ',' . $this -> repeats_table . '.' . implode ( ',' . $this -> repeats_table . '.' , array_keys ( $table_def [ 'fd' ]));
$where = array ();
if ( is_array ( $ids ))
{
array_walk ( $ids , create_function ( '&$val,$key' , '$val = (int) $val;' ));
$where [] = $this -> cal_table . '.cal_id IN (' . implode ( ',' , $ids ) . ')' ;
}
elseif ( is_numeric ( $ids ))
{
$where [] = $this -> cal_table . '.cal_id = ' . ( int ) $ids ;
}
else
{
2009-10-25 19:20:00 +01:00
// We want only the parents to match
2005-11-09 00:15:14 +01:00
$where [ 'cal_uid' ] = $ids ;
2009-07-15 22:35:56 +02:00
$where [ 'cal_reference' ] = 0 ;
2010-01-29 22:42:54 +01:00
$where [ 'cal_recurrence' ] = 0 ;
2005-11-09 00:15:14 +01:00
}
if (( int ) $recur_date )
{
$where [] = 'cal_start >= ' . ( int ) $recur_date ;
}
2008-03-15 15:10:20 +01:00
$events = array ();
2009-11-04 16:00:08 +01:00
foreach ( $this -> db -> select ( $this -> cal_table , " $this->repeats_table .*, $this->cal_table .*,MIN(cal_start) AS cal_start,MIN(cal_end) AS cal_end " ,
2008-03-15 15:10:20 +01:00
$where , __LINE__ , __FILE__ , false , 'GROUP BY ' . $group_by_cols , 'calendar' , 0 ,
2005-11-09 00:15:14 +01:00
" , $this->dates_table LEFT JOIN $this->repeats_table ON $this->dates_table .cal_id= $this->repeats_table .cal_id " .
2008-03-15 15:10:20 +01:00
" WHERE $this->cal_table .cal_id= $this->dates_table .cal_id " ) as $row )
2004-11-07 15:38:00 +01:00
{
2005-11-09 00:15:14 +01:00
$row [ 'recur_exception' ] = $row [ 'recur_exception' ] ? explode ( ',' , $row [ 'recur_exception' ]) : array ();
if ( ! $row [ 'recur_type' ]) $row [ 'recur_type' ] = MCAL_RECUR_NONE ;
2004-11-07 15:38:00 +01:00
$row [ 'alarm' ] = array ();
2008-03-15 15:10:20 +01:00
$events [ $row [ 'cal_id' ]] = egw_db :: strip_array_keys ( $row , 'cal_' );
2005-11-09 00:15:14 +01:00
// if a uid was supplied, convert it for the further code to an id
2008-03-15 15:10:20 +01:00
if ( ! is_array ( $ids ) && ! is_numeric ( $ids )) $ids = $row [ 'cal_id' ];
2004-11-07 15:38:00 +01:00
}
if ( ! $events ) return false ;
2006-03-29 09:01:18 +02:00
2009-08-04 19:14:16 +02:00
foreach ( $events as & $event )
{
if ( ! isset ( $event [ 'uid' ]) || strlen ( $event [ 'uid' ]) < $minimum_uid_length )
{
2009-07-15 22:35:56 +02:00
// event (without uid), not strong enough uid => create new uid
$event [ 'uid' ] = $GLOBALS [ 'egw' ] -> common -> generate_uid ( 'calendar' , $event [ 'id' ]);
$this -> db -> update ( $this -> cal_table , array ( 'cal_uid' => $event [ 'uid' ]),
array ( 'cal_id' => $event [ 'id' ]), __LINE__ , __FILE__ , 'calendar' );
}
2010-02-17 14:29:28 +01:00
if (( int ) $recur_date == 0 &&
$event [ 'recur_type' ] != MCAL_RECUR_NONE &&
! empty ( $event [ 'recur_exception' ]))
{
sort ( $event [ 'recur_exception' ]);
if ( $event [ 'recur_exception' ][ 0 ] < $event [ 'start' ])
{
// leading exceptions => move start and end
$event [ 'end' ] -= $event [ 'start' ] - $event [ 'recur_exception' ][ 0 ];
$event [ 'start' ] = $event [ 'recur_exception' ][ 0 ];
}
}
2009-07-15 22:35:56 +02:00
}
2005-11-09 00:15:14 +01:00
// check if we have a real recurance, if not set $recur_date=0
if ( is_array ( $ids ) || $events [( int ) $ids ][ 'recur_type' ] == MCAL_RECUR_NONE )
2004-11-07 15:38:00 +01:00
{
2005-11-09 00:15:14 +01:00
$recur_date = 0 ;
}
else // adjust the given recurance to the real time, it can be a date without time(!)
{
2007-03-02 14:14:17 +01:00
if ( $recur_date )
{
// also remember recur_date, maybe we need it later, duno now
$recur_date = $events [ $ids ][ 'recur_date' ] = $events [ $ids ][ 'start' ];
}
2004-11-07 15:38:00 +01:00
}
2007-03-02 14:14:17 +01:00
2005-11-09 00:15:14 +01:00
// participants, if a recur_date give, we read that recurance, else the one users from the default entry with recur_date=0
2008-03-15 15:10:20 +01:00
foreach ( $this -> db -> select ( $this -> user_table , '*' , array (
2005-11-09 00:15:14 +01:00
'cal_id' => $ids ,
'cal_recur_date' => $recur_date ,
2008-07-18 13:36:09 +02:00
), __LINE__ , __FILE__ , false , 'ORDER BY cal_user_type DESC,' . self :: STATUS_SORT , 'calendar' ) as $row ) // DESC puts users before resources and contacts
2004-11-07 15:38:00 +01:00
{
2009-08-06 13:29:05 +02:00
// combine all participant data in uid and status values
$uid = self :: combine_user ( $row [ 'cal_user_type' ], $row [ 'cal_user_id' ]);
$status = self :: combine_status ( $row [ 'cal_status' ], $row [ 'cal_quantity' ], $row [ 'cal_role' ]);
$events [ $row [ 'cal_id' ]][ 'participants' ][ $uid ] = $status ;
$events [ $row [ 'cal_id' ]][ 'participant_types' ][ $row [ 'cal_user_type' ]][ $row [ 'cal_user_id' ]] = $status ;
2004-11-07 15:38:00 +01:00
}
// custom fields
2008-03-15 15:10:20 +01:00
foreach ( $this -> db -> select ( $this -> extra_table , '*' , array ( 'cal_id' => $ids ), __LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
2004-11-07 15:38:00 +01:00
{
$events [ $row [ 'cal_id' ]][ '#' . $row [ 'cal_extra_name' ]] = $row [ 'cal_extra_value' ];
}
2006-03-29 09:01:18 +02:00
2004-11-07 15:38:00 +01:00
// alarms, atm. we read all alarms in the system, as this can be done in a single query
foreach (( array ) $this -> async -> read ( 'cal' . ( is_array ( $ids ) ? '' : ':' . ( int ) $ids ) . ':%' ) as $id => $job )
{
list (, $cal_id ) = explode ( ':' , $id );
if ( ! isset ( $events [ $cal_id ])) continue ; // not needed
2006-03-29 09:01:18 +02:00
2004-11-07 15:38:00 +01:00
$alarm = $job [ 'data' ]; // text, enabled
$alarm [ 'id' ] = $id ;
$alarm [ 'time' ] = $job [ 'next' ];
$events [ $cal_id ][ 'alarm' ][ $id ] = $alarm ;
}
//echo "<p>socal::read(".print_r($ids,true).")=<pre>".print_r($events,true)."</pre>\n";
return $events ;
}
2010-01-14 18:01:30 +01:00
2009-12-27 05:21:33 +01:00
/**
* Get maximum modification time of participant data of given event ( s )
2010-01-14 18:01:30 +01:00
*
2009-12-27 05:21:33 +01:00
* This includes ALL recurences of an event series
2010-01-14 18:01:30 +01:00
*
2009-12-27 05:21:33 +01:00
* @ param int | array $ids one or multiple cal_id ' s
* @ return int | array ( array of ) modification timestamp ( s )
*/
function max_user_modified ( $ids )
{
foreach ( $this -> db -> select ( $this -> user_table , 'cal_id,MAX(cal_user_modified) AS user_etag' , array (
'cal_id' => $ids ,
), __LINE__ , __FILE__ , false , 'GROUP BY cal_id' , 'calendar' ) as $row )
{
$etags [ $row [ 'cal_id' ]] = $this -> db -> from_timestamp ( $row [ 'user_etag' ]);
}
//echo "<p>".__METHOD__.'('.array2string($ids).') = '.array2string($etags)."</p>\n";
return is_array ( $ids ) ? $etags : $etags [ $ids ];
}
2005-11-09 00:15:14 +01:00
/**
* generate SQL to filter after a given category ( evtl . incl . subcategories )
2006-03-29 09:01:18 +02:00
*
2009-05-05 00:39:27 +02:00
* @ param array | int $cat_id cat - id or array of cat - ids , or ! $cat_id for none
2005-11-09 00:15:14 +01:00
* @ return string SQL to include in the query
*/
function cat_filter ( $cat_id )
{
$sql = '' ;
if ( $cat_id )
{
2009-07-15 22:35:56 +02:00
if ( ! is_array ( $cat_id ) && !@ $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'common' ][ 'cats_no_subs' ])
2005-11-09 00:15:14 +01:00
{
$cats = $GLOBALS [ 'egw' ] -> categories -> return_all_children ( $cat_id );
}
else
{
$cats = is_array ( $cat_id ) ? $cat_id : array ( $cat_id );
}
array_walk ( $cats , create_function ( '&$val,$key' , '$val = (int) $val;' ));
2007-12-13 17:04:34 +01:00
$sql = '(cal_category' . ( count ( $cats ) > 1 ? " IN (' " . implode ( " ',' " , $cats ) . " ') " : '=' . $this -> db -> quote (( int ) $cat_id ));
2005-11-09 00:15:14 +01:00
foreach ( $cats as $cat )
{
$sql .= ' OR ' . $this -> db -> concat ( " ',' " , 'cal_category' , " ',' " ) . ' LIKE ' . $this -> db -> quote ( '%,' . $cat . ',%' );
}
$sql .= ') ' ;
}
return $sql ;
}
/**
* Searches / lists calendar entries , including repeating ones
*
* @ param int $start startdate of the search / list ( servertime )
* @ param int $end enddate of the search / list ( servertime )
2009-05-05 00:39:27 +02:00
* @ param int | array $users user - id or array of user - id ' s , ! $users means all entries regardless of users
2005-11-09 00:15:14 +01:00
* @ param int $cat_id = 0 mixed category - id or array of cat - id ' s , default 0 = all
* Please note : only a single cat - id , will include all sub - cats ( if the common - pref 'cats_no_subs' is False )
2009-09-29 21:58:51 +02:00
* @ param string $filter = 'all' string filter - name : all ( not rejected ), accepted , unknown , tentative , rejected or hideprivate ( handled elsewhere ! )
2009-05-05 00:39:27 +02:00
* @ param int | boolean $offset = False offset for a limited query or False ( default )
2005-11-09 00:15:14 +01:00
* @ param int $num_rows = 0 number of rows to return if offset set , default 0 = use default in user prefs
2010-05-20 17:12:59 +02:00
* @ param array $params = array ()
2010-06-01 11:28:37 +02:00
* @ param string | array $params [ 'query' ] string : pattern so search for , if unset or empty all matching entries are returned ( no search )
2010-05-20 17:12:59 +02:00
* Please Note : a search never returns repeating events more then once AND does not honor start + end date !!!
2010-06-01 11:28:37 +02:00
* array : everything is directly used as $where
2010-05-20 17:12:59 +02:00
* @ param string $params [ 'order' ] = 'cal_start' column - names plus optional DESC | ASC separted by comma
* @ param string $params [ 'sql_filter' ] sql to be and ' ed into query ( fully quoted )
* @ param string | array $params [ 'cols' ] what to select , default " $this->repeats_table .*, $this->cal_table .*,cal_start,cal_end,cal_recur_date " ,
2009-10-03 09:32:05 +02:00
* if specified and not false an iterator for the rows is returned
2010-05-20 17:12:59 +02:00
* @ param string $params [ 'append' ] SQL to append to the query before $order , eg . for a GROUP BY clause
* @ param array $params [ 'cfs' ] custom fields to query , null = none , array () = all , or array with cfs names
* @ param array $params [ 'users' ] raw parameter as passed to calendar_bo :: search () no memberships resolved !
2009-07-15 22:35:56 +02:00
* @ return array of cal_ids , or false if error in the parameters
2005-11-09 00:15:14 +01:00
*
* ToDo : search custom - fields too
*/
2010-05-20 17:12:59 +02:00
function & search ( $start , $end , $users , $cat_id = 0 , $filter = 'all' , $offset = False , $num_rows = 0 , array $params = array ())
2005-11-09 00:15:14 +01:00
{
2010-06-01 11:28:37 +02:00
//error_log('*** '.__METHOD__.'('.($start ? date('Y-m-d H:i',$start) : '').','.($end ? date('Y-m-d H:i',$end) : '').','.array2string($users).','.array2string($cat_id).",'$filter',".array2string($offset).",$num_rows,".array2string($params).') '.function_backtrace());
2009-05-05 00:39:27 +02:00
2010-05-20 17:12:59 +02:00
$cols = isset ( $params [ 'cols' ]) ? $params [ 'cols' ] : " $this->repeats_table .*, $this->cal_table .*,cal_start,cal_end,cal_recur_date " ;
2005-11-09 00:15:14 +01:00
$where = array ();
2010-05-20 17:12:59 +02:00
if ( is_array ( $params [ 'query' ]))
2005-11-09 00:15:14 +01:00
{
2010-05-20 17:12:59 +02:00
$where = $params [ 'query' ];
2005-11-09 00:15:14 +01:00
}
2010-05-20 17:12:59 +02:00
elseif ( $params [ 'query' ])
2005-11-09 00:15:14 +01:00
{
foreach ( array ( 'cal_title' , 'cal_description' , 'cal_location' ) as $col )
{
2010-06-22 18:59:04 +02:00
$to_or [] = $col . ' ' . $this -> db -> capabilities [ egw_db :: CAPABILITY_CASE_INSENSITIV_LIKE ] . ' ' . $this -> db -> quote ( '%' . $params [ 'query' ] . '%' );
2005-11-09 00:15:14 +01:00
}
$where [] = '(' . implode ( ' OR ' , $to_or ) . ')' ;
}
2010-05-20 17:12:59 +02:00
if ( ! empty ( $params [ 'sql_filter' ]) && is_string ( $params [ 'sql_filter' ]))
2009-12-27 05:21:33 +01:00
{
2010-05-20 17:12:59 +02:00
$where [] = $params [ 'sql_filter' ];
2009-12-27 05:21:33 +01:00
}
2005-11-09 00:15:14 +01:00
if ( $users )
{
$users_by_type = array ();
2009-05-05 00:39:27 +02:00
foreach (( array ) $users as $user )
2005-11-09 00:15:14 +01:00
{
if ( is_numeric ( $user ))
{
$users_by_type [ 'u' ][] = ( int ) $user ;
}
elseif ( is_numeric ( substr ( $user , 1 )))
{
2009-05-05 00:39:27 +02:00
$users_by_type [ $user [ 0 ]][] = ( int ) substr ( $user , 1 );
2005-11-09 00:15:14 +01:00
}
}
2010-04-15 14:52:35 +02:00
$to_or = $user_or = $owner_or = array ();
2010-04-15 15:41:57 +02:00
$useUnionQuery = $this -> db -> capabilities [ 'distinct_on_text' ] && $this -> db -> capabilities [ 'union' ];
2008-03-15 15:10:20 +01:00
$table_def = $this -> db -> get_table_definitions ( 'calendar' , $this -> user_table );
2005-11-09 00:15:14 +01:00
foreach ( $users_by_type as $type => $ids )
{
2010-04-15 14:52:35 +02:00
// when we are able to use Union Querys, we do not OR our query, we save the needed parts for later construction of the union
if ( $useUnionQuery )
2009-09-29 21:58:51 +02:00
{
2010-04-15 14:52:35 +02:00
$user_or [] = $this -> db -> expression ( $table_def , array (
'cal_user_type' => $type ,
'cal_user_id' => $ids ,
));
if ( $type == 'u' && ( $filter == 'owner' ))
{
$cal_table_def = $this -> db -> get_table_definitions ( 'calendar' , $this -> cal_table );
$owner_or [] = $this -> db -> expression ( $cal_table_def , array ( 'cal_owner' => $ids ));
}
}
else
{
$to_or [] = $this -> db -> expression ( $table_def , array (
'cal_user_type' => $type ,
'cal_user_id' => $ids ,
));
if ( $type == 'u' && ( $filter == 'owner' ))
{
$cal_table_def = $this -> db -> get_table_definitions ( 'calendar' , $this -> cal_table );
$to_or [] = $this -> db -> expression ( $cal_table_def , array ( 'cal_owner' => $ids ));
}
2009-09-29 21:58:51 +02:00
}
2005-11-09 00:15:14 +01:00
}
2010-04-15 14:52:35 +02:00
// this is only used, when we cannot use UNIONS
if ( ! $useUnionQuery ) $where [] = '(' . implode ( ' OR ' , $to_or ) . ')' ;
2006-03-29 09:01:18 +02:00
2010-04-23 21:11:24 +02:00
if ( $filter != 'deleted' )
{
2010-05-20 17:12:59 +02:00
$where [ 'cal_deleted' ] = false ;
2010-03-05 21:01:44 +01:00
}
2009-09-29 21:58:51 +02:00
switch ( $filter )
{
2010-04-26 09:08:23 +02:00
case 'showonlypublic' :
2010-05-20 17:12:59 +02:00
$where [ 'cal_public' ] = 1 ;
2010-04-26 14:28:30 +02:00
$where [] = " cal_status != 'R' " ; break ;
2010-03-05 21:01:44 +01:00
case 'deleted' :
2010-05-21 17:09:11 +02:00
$where [ 'cal_deleted' ] = true ; break ;
2009-09-29 21:58:51 +02:00
case 'unknown' :
$where [] = " cal_status='U' " ; break ;
case 'accepted' :
$where [] = " cal_status='A' " ; break ;
case 'tentative' :
$where [] = " cal_status='T' " ; break ;
case 'rejected' :
$where [] = " cal_status='R' " ; break ;
2010-02-17 14:29:28 +01:00
case 'delegated' :
$where [] = " cal_status='D' " ; break ;
2009-09-29 21:58:51 +02:00
case 'all' :
2010-01-29 22:42:54 +01:00
case 'owner' :
2009-09-29 21:58:51 +02:00
break ;
default :
$where [] = " cal_status != 'R' " ;
break ;
}
2005-11-09 00:15:14 +01:00
}
if ( $cat_id )
{
$where [] = $this -> cat_filter ( $cat_id );
}
if ( $start ) $where [] = ( int ) $start . ' < cal_end' ;
if ( $end ) $where [] = 'cal_start < ' . ( int ) $end ;
2006-03-29 09:01:18 +02:00
2010-05-20 17:12:59 +02:00
if ( ! preg_match ( '/^[a-z_ ,]+$/i' , $params [ 'order' ])) $params [ 'order' ] = 'cal_start' ; // gard against SQL injection
2010-06-01 11:28:37 +02:00
2010-04-15 14:52:35 +02:00
if ( $useUnionQuery )
2006-03-03 13:03:33 +01:00
{
2010-01-21 04:00:53 +01:00
// allow apps to supply participants and/or icons
2010-05-21 17:05:31 +02:00
if ( ! isset ( $params [ 'cols' ])) $cols .= ',NULL AS participants,NULL AS icons' ;
2010-03-06 16:49:59 +01:00
2006-03-29 09:01:18 +02:00
// changed the original OR in the query into a union, to speed up the query execution under MySQL 5
$select = array (
'table' => $this -> cal_table ,
2010-04-22 18:09:36 +02:00
'join' => " JOIN $this->dates_table ON $this->cal_table .cal_id= $this->dates_table .cal_id JOIN $this->user_table ON $this->cal_table .cal_id= $this->user_table .cal_id LEFT JOIN $this->repeats_table ON $this->cal_table .cal_id= $this->repeats_table .cal_id " ,
2009-05-05 00:39:27 +02:00
'cols' => $cols ,
2006-03-29 09:01:18 +02:00
'where' => $where ,
2008-03-15 15:10:20 +01:00
'app' => 'calendar' ,
2010-05-20 17:12:59 +02:00
'append' => $params [ 'append' ],
2006-03-29 09:01:18 +02:00
);
2010-04-23 08:52:48 +02:00
// we check if there are parts to use for the construction of our UNION query,
2010-04-15 14:52:35 +02:00
// as replace the OR by construction of a suitable UNION for performance reasons
if ( ! empty ( $owner_or ) ||! empty ( $user_or ))
{
if ( ! empty ( $owner_or ) && ! empty ( $user_or ))
{
// if the query is to be filtered by owner OR user we need 4 selects for the union
//_debug_array($owner_or);
2010-04-15 15:41:57 +02:00
$selects = array ();
2010-04-23 08:52:48 +02:00
foreach ( array_keys ( $user_or ) as $key )
2010-04-15 15:41:57 +02:00
{
2010-04-16 09:55:43 +02:00
$selects [] = $select ;
2010-04-15 15:41:57 +02:00
$selects [ count ( $selects ) - 1 ][ 'where' ][] = $user_or [ $key ];
$selects [ count ( $selects ) - 1 ][ 'where' ][] = 'recur_type IS NULL AND cal_recur_date=0' ;
2010-04-16 09:55:43 +02:00
$selects [] = $select ;
2010-04-15 15:41:57 +02:00
$selects [ count ( $selects ) - 1 ][ 'where' ][] = $user_or [ $key ];
$selects [ count ( $selects ) - 1 ][ 'where' ][] = 'cal_recur_date=cal_start' ;
}
2010-04-16 09:55:43 +02:00
$selects [] = $select ;
2010-04-15 15:41:57 +02:00
$selects [ count ( $selects ) - 1 ][ 'where' ][] = $owner_or ;
$selects [ count ( $selects ) - 1 ][ 'where' ][] = 'recur_type IS NULL AND cal_recur_date=0' ;
2010-04-16 09:55:43 +02:00
$selects [] = $select ;
2010-04-15 15:41:57 +02:00
$selects [ count ( $selects ) - 1 ][ 'where' ][] = $owner_or ;
$selects [ count ( $selects ) - 1 ][ 'where' ][] = 'cal_recur_date=cal_start' ;
2010-04-15 14:52:35 +02:00
}
else
{
// if the query is to be filtered only by user we need 2 selects for the union
2010-04-15 15:41:57 +02:00
$selects = array ();
foreach ( array_keys ( $user_or ) as $key )
{
2010-04-16 09:55:43 +02:00
$selects [] = $select ;
2010-04-15 15:41:57 +02:00
$selects [ count ( $selects ) - 1 ][ 'where' ][] = $user_or [ $key ];
$selects [ count ( $selects ) - 1 ][ 'where' ][] = 'recur_type IS NULL AND cal_recur_date=0' ;
2010-04-16 09:55:43 +02:00
$selects [] = $select ;
2010-04-15 15:41:57 +02:00
$selects [ count ( $selects ) - 1 ][ 'where' ][] = $user_or [ $key ];
$selects [ count ( $selects ) - 1 ][ 'where' ][] = 'cal_recur_date=cal_start' ;
}
2010-04-15 14:52:35 +02:00
}
}
else
{
// if the query is to be filtered by neither by user nor owner (should not happen?) we need 2 selects for the union
$selects = array ( $select , $select );
$selects [ 0 ][ 'where' ][] = 'recur_type IS NULL AND cal_recur_date=0' ;
$selects [ 1 ][ 'where' ][] = 'cal_recur_date=cal_start' ;
}
2006-03-29 09:01:18 +02:00
if ( is_numeric ( $offset )) // get the total too
{
// we only select cal_table.cal_id (and not cal_table.*) to be able to use DISTINCT (eg. MsSQL does not allow it for text-columns)
2010-04-16 09:55:43 +02:00
$countSelects = count ( $selects );
2010-04-23 08:52:48 +02:00
foreach ( array_keys ( $selects ) as $key )
2010-04-16 09:55:43 +02:00
{
2010-04-23 08:52:48 +02:00
$selects [ $key ][ 'cols' ] = " DISTINCT $this->repeats_table .*, $this->cal_table .cal_id,cal_start,cal_end,cal_recur_date " ;
2010-04-16 09:55:43 +02:00
//$selects[0]['cols'] = $selects[1]['cols'] = "DISTINCT $this->repeats_table.*,$this->cal_table.cal_id,cal_start,cal_end,cal_recur_date";
}
2010-06-01 11:28:37 +02:00
if ( ! isset ( $param [ 'cols' ])) self :: get_union_selects ( $selects , $start , $end , $users , $cat_id , $filter , $params [ 'query' ], $params [ 'users' ]);
2006-03-03 13:03:33 +01:00
2008-03-15 15:10:20 +01:00
$this -> total = $this -> db -> union ( $selects , __LINE__ , __FILE__ ) -> NumRows ();
2010-04-16 09:55:43 +02:00
$i = 0 ;
2010-04-23 08:52:48 +02:00
foreach ( array_keys ( $selects ) as $key )
2010-04-16 09:55:43 +02:00
{
if ( $i >= $countSelects ) continue ;
2010-05-17 17:40:06 +02:00
$i ++ ;
2010-04-16 09:55:43 +02:00
$selects [ $key ][ 'cols' ] = $select [ 'cols' ]; // restore the original cols
//$selects[0]['cols'] = $selects[1]['cols'] = $select['cols']; // restore the original cols
}
$i = 0 ;
$selections = array ();
foreach ( array_keys ( $selects ) as $key )
{
if ( $i >= $countSelects ) continue ;
$i ++ ;
$selections [] = $selects [ $key ];
}
2005-11-09 00:15:14 +01:00
2010-04-16 09:55:43 +02:00
$selects = $selections ;
2006-03-29 09:01:18 +02:00
}
2010-06-01 11:28:37 +02:00
if ( ! isset ( $param [ 'cols' ])) self :: get_union_selects ( $selects , $start , $end , $users , $cat_id , $filter , $params [ 'query' ], $params [ 'users' ]);
2010-05-20 17:12:59 +02:00
$rs = $this -> db -> union ( $selects , __LINE__ , __FILE__ , $params [ 'order' ], $offset , $num_rows );
2006-03-29 09:01:18 +02:00
}
else // MsSQL oder MySQL 3.23
2005-11-09 00:15:14 +01:00
{
2006-03-29 09:01:18 +02:00
$where [] = '(recur_type IS NULL AND cal_recur_date=0 OR cal_recur_date=cal_start)' ;
//_debug_array($where);
if ( is_numeric ( $offset )) // get the total too
{
// we only select cal_table.cal_id (and not cal_table.*) to be able to use DISTINCT (eg. MsSQL does not allow it for text-columns)
2008-03-15 15:10:20 +01:00
$this -> total = $this -> db -> select ( $this -> cal_table , " DISTINCT $this->repeats_table .*, $this->cal_table .cal_id,cal_start,cal_end,cal_recur_date " ,
$where , __LINE__ , __FILE__ , false , '' , 'calendar' , 0 ,
" JOIN $this->dates_table ON $this->cal_table .cal_id= $this->dates_table .cal_id JOIN $this->user_table ON $this->cal_table .cal_id= $this->user_table .cal_id LEFT JOIN $this->repeats_table ON $this->cal_table .cal_id= $this->repeats_table .cal_id " ) -> NumRows ();
2006-03-29 09:01:18 +02:00
}
2009-05-05 00:39:27 +02:00
$rs = $this -> db -> select ( $this -> cal_table ,( $this -> db -> capabilities [ 'distinct_on_text' ] ? 'DISTINCT ' : '' ) . $cols ,
2010-05-20 17:12:59 +02:00
$where , __LINE__ , __FILE__ , $offset , $params [ 'append' ] . ' ORDER BY ' . $params [ 'order' ], 'calendar' , $num_rows ,
2006-03-29 09:01:18 +02:00
" JOIN $this->dates_table ON $this->cal_table .cal_id= $this->dates_table .cal_id JOIN $this->user_table ON $this->cal_table .cal_id= $this->user_table .cal_id LEFT JOIN $this->repeats_table ON $this->cal_table .cal_id= $this->repeats_table .cal_id " );
2006-03-02 08:02:33 +01:00
}
2010-06-01 11:28:37 +02:00
if ( isset ( $params [ 'cols' ]))
2009-05-05 00:39:27 +02:00
{
return $rs ; // if colums are specified we return the recordset / iterator
}
2006-03-29 09:01:18 +02:00
$events = $ids = $recur_dates = $recur_ids = array ();
2008-03-15 15:10:20 +01:00
foreach ( $rs as $row )
2005-11-09 00:15:14 +01:00
{
2010-01-19 23:20:44 +01:00
$id = $row [ 'cal_id' ];
if ( is_numeric ( $id )) $ids [] = $id ;
2008-03-20 13:49:34 +01:00
if ( $row [ 'cal_recur_date' ])
2005-11-09 00:15:14 +01:00
{
2008-03-20 13:49:34 +01:00
$id .= '-' . $row [ 'cal_recur_date' ];
$recur_dates [] = $row [ 'cal_recur_date' ];
2005-11-09 00:15:14 +01:00
}
2010-01-21 04:00:53 +01:00
if ( $row [ 'participants' ])
2010-02-01 11:35:05 +01:00
{
$row [ 'participants' ] = explode ( ',' , $row [ 'participants' ]);
$row [ 'participants' ] = array_combine ( $row [ 'participants' ],
array_fill ( 0 , count ( $row [ 'participants' ]), '' ));
}
else
{
$row [ 'participants' ] = array ();
}
$row [ 'alarm' ] = array ();
2005-11-09 00:15:14 +01:00
$row [ 'recur_exception' ] = $row [ 'recur_exception' ] ? explode ( ',' , $row [ 'recur_exception' ]) : array ();
2008-03-15 15:10:20 +01:00
$events [ $id ] = egw_db :: strip_array_keys ( $row , 'cal_' );
2005-11-09 00:15:14 +01:00
}
2010-01-19 23:20:44 +01:00
//_debug_array($events);
2010-02-01 11:35:05 +01:00
if ( count ( $ids ))
2005-11-09 00:15:14 +01:00
{
// now ready all users with the given cal_id AND (cal_recur_date=0 or the fitting recur-date)
// This will always read the first entry of each recuring event too, we eliminate it later
$recur_dates [] = 0 ;
2009-08-04 19:14:16 +02:00
$utcal_id_view = " (SELECT * FROM " . $this -> user_table . " WHERE cal_id IN ( " . implode ( ',' , array_unique ( $ids )) . " )) utcalid " ;
2009-03-16 14:50:03 +01:00
//$utrecurdate_view = " (select * from ".$this->user_table." where cal_recur_date in (".implode(',',array_unique($recur_dates)).")) utrecurdates ";
foreach ( $this -> db -> select ( $utcal_id_view , '*' , array (
//'cal_id' => array_unique($ids),
'cal_recur_date' => $recur_dates ,
), __LINE__ , __FILE__ , false , 'ORDER BY cal_id,cal_user_type DESC,' . self :: STATUS_SORT , 'calendar' , $num_rows = 0 , $join = '' ,
$this -> db -> get_table_definitions ( 'calendar' , $this -> user_table )) as $row ) // DESC puts users before resources and contacts
2005-11-09 00:15:14 +01:00
{
$id = $row [ 'cal_id' ];
if ( $row [ 'cal_recur_date' ]) $id .= '-' . $row [ 'cal_recur_date' ];
2009-11-03 17:13:45 +01:00
if ( ! in_array ( $id ,( array ) $recur_ids [ $row [ 'cal_id' ]])) $recur_ids [ $row [ 'cal_id' ]][] = $id ;
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
if ( ! isset ( $events [ $id ])) continue ; // not needed first entry of recuring event
2006-03-29 09:01:18 +02:00
2009-08-06 13:29:05 +02:00
// combine all participant data in uid and status values
$events [ $id ][ 'participants' ][ self :: combine_user ( $row [ 'cal_user_type' ], $row [ 'cal_user_id' ])] =
self :: combine_status ( $row [ 'cal_status' ], $row [ 'cal_quantity' ], $row [ 'cal_role' ]);
2005-11-09 00:15:14 +01:00
}
2009-10-03 09:32:05 +02:00
//custom fields are not shown in the regular views, so we only query them, if explicitly required
2010-05-20 17:12:59 +02:00
if ( ! is_null ( $params [ 'cfs' ]))
2005-11-09 00:15:14 +01:00
{
2009-11-03 17:13:45 +01:00
$where = array ( 'cal_id' => $ids );
2010-05-20 17:12:59 +02:00
if ( $params [ 'cfs' ]) $where [ 'cal_extra_name' ] = $params [ 'cfs' ];
2009-11-03 17:13:45 +01:00
foreach ( $this -> db -> select ( $this -> extra_table , '*' , $where ,
2009-10-03 09:32:05 +02:00
__LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
2005-11-09 00:15:14 +01:00
{
2009-10-03 09:32:05 +02:00
foreach (( array ) $recur_ids [ $row [ 'cal_id' ]] as $id )
2005-11-09 00:15:14 +01:00
{
2009-10-03 09:32:05 +02:00
if ( isset ( $events [ $id ]))
{
$events [ $id ][ '#' . $row [ 'cal_extra_name' ]] = $row [ 'cal_extra_value' ];
}
2005-11-09 00:15:14 +01:00
}
}
}
// alarms, atm. we read all alarms in the system, as this can be done in a single query
foreach (( array ) $this -> async -> read ( 'cal' . ( is_array ( $ids ) ? '' : ':' . ( int ) $ids ) . ':%' ) as $id => $job )
{
2006-03-07 20:03:42 +01:00
list (, $cal_id ) = explode ( ':' , $id );
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
$alarm = $job [ 'data' ]; // text, enabled
$alarm [ 'id' ] = $id ;
$alarm [ 'time' ] = $job [ 'next' ];
2006-03-29 09:01:18 +02:00
2006-03-07 20:03:42 +01:00
$event_start = $alarm [ 'time' ] + $alarm [ 'offset' ];
2006-03-29 09:01:18 +02:00
2006-03-07 20:03:42 +01:00
if ( isset ( $events [ $cal_id ])) // none recuring event
{
$events [ $cal_id ][ 'alarm' ][ $id ] = $alarm ;
}
elseif ( isset ( $events [ $cal_id . '-' . $event_start ])) // recuring event
{
$events [ $cal_id . '-' . $event_start ][ 'alarm' ][ $id ] = $alarm ;
2006-03-29 09:01:18 +02:00
}
2005-11-09 00:15:14 +01:00
}
}
//echo "<p>socal::search\n"; _debug_array($events);
return $events ;
}
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
/**
* Data returned by calendar_search_union hook
*/
private static $integration_data ;
2006-03-29 09:01:18 +02:00
2010-01-19 23:20:44 +01:00
/**
* Ask other apps if they want to participate in calendar search / display
*
* @ param & $selects parts of union query
* @ param $start see search ()
* @ param $end
2010-05-20 17:12:59 +02:00
* @ param $users as used in calendar_so ( $users_raw plus all members and memberships added by calendar_bo )
2010-01-19 23:20:44 +01:00
* @ param $cat_id
* @ param $filter
* @ param $query
2010-05-20 17:12:59 +02:00
* @ param $users_raw as passed to calendar_bo :: search ( no members and memberships added )
2010-01-19 23:20:44 +01:00
*/
2010-05-20 17:12:59 +02:00
private static function get_union_selects ( array & $selects , $start , $end , $users , $cat_id , $filter , $query , $users_raw )
2010-01-19 23:20:44 +01:00
{
2010-05-21 17:05:31 +02:00
if ( in_array ( basename ( $_SERVER [ 'SCRIPT_FILENAME' ]), array ( 'groupdav.php' , 'rpc.php' , 'xmlrpc.php' )) ||
! in_array ( $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ], array ( 'calendar' , 'home' )))
2010-01-24 04:50:40 +01:00
{
2010-01-29 22:42:54 +01:00
return ; // disable integration for GroupDAV, SyncML, ...
2010-01-24 04:50:40 +01:00
}
2010-01-22 00:36:05 +01:00
self :: $integration_data = $GLOBALS [ 'egw' ] -> hooks -> process ( array (
2010-01-19 23:20:44 +01:00
'location' => 'calendar_search_union' ,
2010-01-29 22:42:54 +01:00
'cols' => $selects [ 0 ][ 'cols' ], // cols to return
2010-01-19 23:20:44 +01:00
'start' => $start ,
'end' => $end ,
'users' => $users ,
2010-05-20 17:12:59 +02:00
'users_raw' => $users_raw ,
2010-01-19 23:20:44 +01:00
'cat_id' => $cat_id ,
'filter' => $filter ,
'query' => $query ,
));
2010-01-22 00:36:05 +01:00
foreach ( self :: $integration_data as $app => $data )
2010-01-19 23:20:44 +01:00
{
if ( is_array ( $data [ 'selects' ]))
{
2010-01-22 00:36:05 +01:00
//echo $app; _debug_array($data);
2010-01-19 23:20:44 +01:00
$selects = array_merge ( $selects , $data [ 'selects' ]);
}
}
}
2010-01-29 22:42:54 +01:00
2010-01-22 00:36:05 +01:00
/**
* Get data from last 'calendar_search_union' hook call
2010-01-29 22:42:54 +01:00
*
2010-01-22 00:36:05 +01:00
* @ return array
*/
public static function get_integration_data ()
{
return self :: $integration_data ;
}
2010-01-29 22:42:54 +01:00
2010-04-23 08:52:48 +02:00
/**
* Return union cols constructed from application cols and required cols
*
* Every col not supplied in $app_cols get returned as NULL .
*
* @ param array $app_cols required name => own name pairs
* @ param string | array $required array or comma separated column names or table .*
* @ param string $required_app = 'calendar'
* @ return string cols for union query to match ones supplied in $required
*/
public static function union_cols ( array $app_cols , $required , $required_app = 'calendar' )
{
// remove evtl. used DISTINCT, we currently dont need it
if (( $distinct = substr ( $required , 0 , 9 ) == 'DISTINCT ' ))
{
$required = substr ( $required , 9 );
}
$return_cols = array ();
foreach ( is_array ( $required ) ? $required : explode ( ',' , $required ) as $cols )
{
if ( substr ( $cols , - 2 ) == '.*' )
{
$cols = self :: get_columns ( $required_app , substr ( $cols , 0 , - 2 ));
}
elseif ( strpos ( $cols , ' AS ' ) !== false )
{
list (, $cols ) = explode ( ' AS ' , $cols );
}
foreach (( array ) $cols as $col )
{
if ( substr ( $col , 0 , 7 ) == 'egw_cal' ) // remove table name
{
2010-04-27 20:35:14 +02:00
$col = preg_replace ( '/^egw_cal[a-z_]*\./' , '' , $col );
2010-04-23 08:52:48 +02:00
}
if ( isset ( $app_cols [ $col ]))
{
$return_cols [] = $app_cols [ $col ];
}
else
{
$return_cols [] = 'NULL' ;
}
}
}
return implode ( ',' , $return_cols );
}
/**
* Get columns of given table , taking into account historically different column order of egw_cal table
*
* @ param string $app
* @ param string $table
* @ return array of column names
*/
static private function get_columns ( $app , $table )
{
if ( $table != 'egw_cal' )
{
$table_def = $GLOBALS [ 'egw' ] -> db -> get_table_definitions ( $app , $table );
$cols = array_keys ( $table_def [ 'fd' ]);
}
else
{
// special handling for egw_cal, as old databases have a different column order!!!
$cols =& egw_cache :: getSession ( __CLASS__ , $table );
if ( is_null ( $cols ))
{
$meta = $GLOBALS [ 'egw' ] -> db -> metadata ( $table , true );
$cols = array_keys ( $meta [ 'meta' ]);
}
}
return $cols ;
}
2005-11-09 00:15:14 +01:00
/**
* Checks for conflicts
*/
/* folowing SQL checks for conflicts completly on DB level
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
SELECT cal_user_type , cal_user_id , SUM ( cal_quantity )
FROM egw_cal , egw_cal_dates , egw_cal_user
LEFT JOIN egw_cal_repeats ON egw_cal . cal_id = egw_cal_repeats . cal_id
WHERE egw_cal . cal_id = egw_cal_dates . cal_id
AND egw_cal . cal_id = egw_cal_user . cal_id
AND (
recur_type IS NULL
AND cal_recur_date = 0
OR cal_recur_date = cal_start
)
AND (
(
cal_user_type = 'u' # user of the checked event
AND cal_user_id
IN ( 7 , 5 )
)
AND 1118822400 < cal_end # start- and end-time of the checked event
AND cal_start < 1118833200
)
AND egw_cal . cal_id != 26 # id of the checked event
AND cal_non_blocking != 1
AND cal_status != 'R'
GROUP BY cal_user_type , cal_user_id
ORDER BY cal_user_type , cal_usre_id
2006-03-29 09:01:18 +02:00
*/
2005-11-09 00:15:14 +01:00
/**
* Saves or creates an event
*
* We always set cal_modified and cal_modifier and for new events cal_uid .
* All other column are only written if they are set in the $event parameter !
*
* @ param array $event
* @ param boolean & $set_recurrences on return : true if the recurrences need to be written , false otherwise
2009-08-10 11:24:39 +02:00
* @ param int & $set_recurrences_start = 0 on return : time from which on the recurrences should be rebuilt , default 0 = all
2005-11-09 00:15:14 +01:00
* @ param int $change_since = 0 time from which on the repetitions should be changed , default 0 = all
2008-05-08 00:12:25 +02:00
* @ param int & $etag etag = null etag to check or null , on return new etag
2009-05-05 00:39:27 +02:00
* @ return boolean | int false on error , 0 if etag does not match , cal_id otherwise
2005-11-09 00:15:14 +01:00
*/
2009-08-10 11:24:39 +02:00
function save ( $event , & $set_recurrences , & $set_recurrences_start = 0 , $change_since = 0 , & $etag = null )
2005-11-09 00:15:14 +01:00
{
2009-07-23 18:14:22 +02:00
if ( isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ]))
{
2009-07-15 22:35:56 +02:00
$minimum_uid_length = $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ 'syncml' ][ 'minimum_uid_length' ];
2009-07-23 18:14:22 +02:00
}
else
{
2009-07-15 22:35:56 +02:00
$minimum_uid_length = 8 ;
}
2010-02-17 14:29:28 +01:00
$old_min = $old_duration = 0 ;
2009-08-07 12:20:58 +02:00
//echo '<p>'.__METHOD__.'('.array2string($event).",$change_since) event="; _debug_array($event);
//error_log(__METHOD__.'('.array2string($event).",$set_recurrences,$change_since,$etag)");
2005-11-09 00:15:14 +01:00
$cal_id = ( int ) $event [ 'id' ];
unset ( $event [ 'id' ]);
$set_recurrences = ! $cal_id && $event [ 'recur_type' ] != MCAL_RECUR_NONE ;
2006-03-29 09:01:18 +02:00
2009-11-27 07:46:32 +01:00
if ( $event [ 'recur_type' ] != MCAL_RECUR_NONE &&
! ( int ) $event [ 'recur_interval' ])
{
$event [ 'recur_interval' ] = 1 ;
}
2005-11-09 00:15:14 +01:00
// add colum prefix 'cal_' if there's not already a 'recur_' prefix
foreach ( $event as $col => $val )
{
2009-11-04 08:57:55 +01:00
if ( $col [ 0 ] != '#' && substr ( $col , 0 , 6 ) != 'recur_' && $col != 'alarm' && $col != 'tz_id' )
2005-11-09 00:15:14 +01:00
{
$event [ 'cal_' . $col ] = $val ;
unset ( $event [ $col ]);
}
}
2010-01-29 22:42:54 +01:00
// ensure that we find mathing entries later on
if ( ! is_array ( $event [ 'cal_category' ]))
{
$categories = array_unique ( explode ( ',' , $event [ 'cal_category' ]));
sort ( $categories );
}
else
{
$categories = array_unique ( $event [ 'cal_category' ]);
}
sort ( $categories , SORT_NUMERIC );
$event [ 'cal_category' ] = implode ( ',' , $categories );
2005-11-09 00:15:14 +01:00
2008-05-08 00:12:25 +02:00
if ( $cal_id )
2008-01-15 09:21:25 +01:00
{
2008-05-08 00:12:25 +02:00
$where = array ( 'cal_id' => $cal_id );
2009-11-12 20:11:27 +01:00
// read only timezone id, to check if it is changed
if ( $event [ 'recur_type' ] != MCAL_RECUR_NONE )
{
$old_tz_id = $this -> db -> select ( $this -> cal_table , 'tz_id' , $where , __LINE__ , __FILE__ , 'calendar' ) -> fetchColumn ();
}
2008-05-08 00:12:25 +02:00
if ( ! is_null ( $etag )) $where [ 'cal_etag' ] = $etag ;
unset ( $event [ 'cal_etag' ]);
$event [] = 'cal_etag=cal_etag+1' ; // always update the etag, even if none given to check
$this -> db -> update ( $this -> cal_table , $event , $where , __LINE__ , __FILE__ , 'calendar' );
if ( ! is_null ( $etag ) && $this -> db -> affected_rows () < 1 )
2008-01-15 09:21:25 +01:00
{
2008-05-08 00:12:25 +02:00
return 0 ; // wrong etag, someone else updated the entry
2008-01-15 09:21:25 +01:00
}
2008-05-08 00:12:25 +02:00
if ( ! is_null ( $etag )) ++ $etag ;
2005-11-09 00:15:14 +01:00
}
else
{
2009-07-15 22:35:56 +02:00
// new event
2005-11-09 00:15:14 +01:00
if ( ! $event [ 'cal_owner' ]) $event [ 'cal_owner' ] = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
if ( ! $event [ 'cal_id' ] && ! isset ( $event [ 'cal_uid' ])) $event [ 'cal_uid' ] = '' ; // uid is NOT NULL!
2008-03-17 10:06:08 +01:00
$this -> db -> insert ( $this -> cal_table , $event , false , __LINE__ , __FILE__ , 'calendar' );
2005-11-09 00:15:14 +01:00
if ( ! ( $cal_id = $this -> db -> get_last_insert_id ( $this -> cal_table , 'cal_id' )))
{
return false ;
}
2008-05-08 00:12:25 +02:00
$etag = 0 ;
2009-07-15 22:35:56 +02:00
}
2009-07-23 18:14:22 +02:00
if ( ! isset ( $event [ 'cal_uid' ]) || strlen ( $event [ 'cal_uid' ]) < $minimum_uid_length )
{
2009-07-15 22:35:56 +02:00
// event (without uid), not strong enough uid
$event [ 'cal_uid' ] = $GLOBALS [ 'egw' ] -> common -> generate_uid ( 'calendar' , $cal_id );
$this -> db -> update ( $this -> cal_table , array ( 'cal_uid' => $event [ 'cal_uid' ]),
array ( 'cal_id' => $event [ 'cal_id' ]), __LINE__ , __FILE__ , 'calendar' );
2005-11-09 00:15:14 +01:00
}
2010-06-26 17:58:33 +02:00
if ( $event [ 'recur_type' ] == MCAL_RECUR_NONE )
{
$this -> db -> delete ( $this -> dates_table , array (
'cal_id' => $cal_id ),
__LINE__ , __FILE__ , 'calendar' );
// delete all user-records, with recur-date != 0
$this -> db -> delete ( $this -> user_table , array (
'cal_id' => $cal_id , 'cal_recur_date != 0' ),
__LINE__ , __FILE__ , 'calendar' );
$this -> db -> delete ( $this -> repeats_table , array (
'cal_id' => $cal_id ),
__LINE__ , __FILE__ , 'calendar' );
}
else // write information about recuring event, if recur_type is present in the array
2005-11-09 00:15:14 +01:00
{
2009-07-17 19:16:34 +02:00
// fetch information about the currently saved (old) event
$old_min = ( int ) $this -> db -> select ( $this -> dates_table , 'MIN(cal_start)' , array ( 'cal_id' => $cal_id ), __LINE__ , __FILE__ , false , '' , 'calendar' ) -> fetchColumn ();
$old_duration = ( int ) $this -> db -> select ( $this -> dates_table , 'MIN(cal_end)' , array ( 'cal_id' => $cal_id ), __LINE__ , __FILE__ , false , '' , 'calendar' ) -> fetchColumn () - $old_min ;
$old_repeats = $this -> db -> select ( $this -> repeats_table , '*' , array ( 'cal_id' => $cal_id ), __LINE__ , __FILE__ , false , '' , 'calendar' ) -> fetch ();
$old_exceptions = $old_repeats [ 'recur_exception' ] ? explode ( ',' , $old_repeats [ 'recur_exception' ]) : array ();
2010-03-07 00:06:43 +01:00
if ( ! empty ( $old_exceptions ))
{
sort ( $old_exceptions );
if ( $old_min > $old_exceptions [ 0 ]) $old_min = $old_exceptions [ 0 ];
}
2009-07-15 22:35:56 +02:00
2009-08-10 11:24:39 +02:00
$event [ 'recur_exception' ] = is_array ( $event [ 'recur_exception' ]) ? $event [ 'recur_exception' ] : array ();
2010-03-07 00:06:43 +01:00
if ( ! empty ( $event [ 'recur_exception' ]))
{
sort ( $event [ 'recur_exception' ]);
}
$where = array ( 'cal_id' => $cal_id ,
'cal_recur_date' => 0 );
$old_participants = array ();
foreach ( $this -> db -> select ( $this -> user_table , 'cal_user_type,cal_user_id,cal_status,cal_quantity,cal_role' , $where ,
__LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
{
$uid = self :: combine_user ( $row [ 'cal_user_type' ], $row [ 'cal_user_id' ]);
$status = self :: combine_status ( $row [ 'cal_status' ], $row [ 'cal_quantity' ], $row [ 'cal_role' ]);
$old_participants [ $uid ] = $status ;
}
2009-08-10 11:24:39 +02:00
// re-check: did so much recurrence data change that we have to rebuild it from scratch?
if ( ! $set_recurrences )
2005-11-09 00:15:14 +01:00
{
2009-08-10 11:24:39 +02:00
$set_recurrences = ( isset ( $event [ 'cal_start' ]) && ( int ) $old_min != ( int ) $event [ 'cal_start' ]) ||
$event [ 'recur_type' ] != $old_repeats [ 'recur_type' ] || $event [ 'recur_data' ] != $old_repeats [ 'recur_data' ] ||
2009-11-12 20:11:27 +01:00
( int ) $event [ 'recur_interval' ] != ( int ) $old_repeats [ 'recur_interval' ] || $event [ 'tz_id' ] != $old_tz_id ;
2005-11-09 00:15:14 +01:00
}
2009-08-10 11:24:39 +02:00
if ( $set_recurrences )
2005-11-09 00:15:14 +01:00
{
2009-08-10 11:24:39 +02:00
// too much recurrence data has changed, we have to do a rebuild from scratch
// delete all, but the lowest dates record
$this -> db -> delete ( $this -> dates_table , array (
'cal_id' => $cal_id ,
'cal_start > ' . ( int ) $old_min ,
), __LINE__ , __FILE__ , 'calendar' );
2009-07-17 19:16:34 +02:00
2009-08-10 11:24:39 +02:00
// delete all user-records, with recur-date != 0
$this -> db -> delete ( $this -> user_table , array (
'cal_id' => $cal_id ,
'cal_recur_date != 0' ,
), __LINE__ , __FILE__ , 'calendar' );
}
else
2009-07-17 19:16:34 +02:00
{
2009-08-10 11:24:39 +02:00
// we adjust some possibly changed recurrences manually
// deleted exceptions: re-insert recurrences into the user and dates table
2010-03-07 00:06:43 +01:00
if ( count ( $deleted_exceptions = array_diff ( $old_exceptions , $event [ 'recur_exception' ])))
2009-07-17 19:16:34 +02:00
{
2010-03-07 00:06:43 +01:00
if ( isset ( $event [ 'cal_participants' ]))
{
$participants = $event [ 'cal_participants' ];
}
else
{
// use old default
$participants = $old_participants ;
}
2009-08-10 11:24:39 +02:00
foreach ( $deleted_exceptions as $id => $deleted_exception )
2009-07-17 19:16:34 +02:00
{
2009-08-10 11:24:39 +02:00
// rebuild participants for the re-inserted recurrence
$this -> recurrence ( $cal_id , $deleted_exception , $deleted_exception + $old_duration , $participants );
2009-07-17 19:16:34 +02:00
}
}
2009-08-10 11:24:39 +02:00
// check if recurrence enddate was adjusted
if ( isset ( $event [ 'recur_enddate' ]))
{
// recurrences need to be truncated
if (( int ) $event [ 'recur_enddate' ] > 0 &&
(( int ) $old_repeats [ 'recur_enddate' ] == 0 || ( int ) $old_repeats [ 'recur_enddate' ] > ( int ) $event [ 'recur_enddate' ])
)
{
$this -> db -> delete ( $this -> user_table , array ( 'cal_id' => $cal_id , 'cal_recur_date > ' . ( $event [ 'recur_enddate' ] + 1 * DAY_s )), __LINE__ , __FILE__ , 'calendar' );
$this -> db -> delete ( $this -> dates_table , array ( 'cal_id' => $cal_id , 'cal_start > ' . ( $event [ 'recur_enddate' ] + 1 * DAY_s )), __LINE__ , __FILE__ , 'calendar' );
}
// recurrences need to be expanded
if ((( int ) $event [ 'recur_enddate' ] == 0 && ( int ) $old_repeats [ 'recur_enddate' ] > 0 )
|| (( int ) $event [ 'recur_enddate' ] > 0 && ( int ) $old_repeats [ 'recur_enddate' ] > 0 && ( int ) $old_repeats [ 'recur_enddate' ] < ( int ) $event [ 'recur_enddate' ])
)
{
$set_recurrences = true ;
$set_recurrences_start = ( $old_repeats [ 'recur_enddate' ] + 1 * DAY_s );
}
}
// truncate recurrences by given exceptions
if ( count ( $event [ 'recur_exception' ]))
{
// added and existing exceptions: delete the execeptions from the user and dates table, it could be the first time
$this -> db -> delete ( $this -> user_table , array ( 'cal_id' => $cal_id , 'cal_recur_date' => $event [ 'recur_exception' ]), __LINE__ , __FILE__ , 'calendar' );
$this -> db -> delete ( $this -> dates_table , array ( 'cal_id' => $cal_id , 'cal_start' => $event [ 'recur_exception' ]), __LINE__ , __FILE__ , 'calendar' );
}
2005-11-09 00:15:14 +01:00
}
2009-07-23 18:14:22 +02:00
2009-08-10 11:24:39 +02:00
// write the repeats table
2009-07-15 22:35:56 +02:00
$event [ 'recur_exception' ] = empty ( $event [ 'recur_exception' ]) ? null : implode ( ',' , $event [ 'recur_exception' ]);
2008-05-16 13:02:46 +02:00
unset ( $event [ 0 ]); // unset the 'etag=etag+1', as it's not in the repeats table
2010-06-26 17:58:33 +02:00
$this -> db -> insert ( $this -> repeats_table , $event , array ( 'cal_id' => $cal_id ), __LINE__ , __FILE__ , 'calendar' );
2005-11-09 00:15:14 +01:00
}
// update start- and endtime if present in the event-array, evtl. we need to move all recurrences
if ( isset ( $event [ 'cal_start' ]) && isset ( $event [ 'cal_end' ]))
{
2010-02-17 14:29:28 +01:00
$this -> move ( $cal_id , $event [ 'cal_start' ], $event [ 'cal_end' ], ! $cal_id ? false : $change_since , $old_min , $old_min + $old_duration );
2005-11-09 00:15:14 +01:00
}
// update participants if present in the event-array
if ( isset ( $event [ 'cal_participants' ]))
{
$this -> participants ( $cal_id , $event [ 'cal_participants' ], ! $cal_id ? false : $change_since );
}
// Custom fields
foreach ( $event as $name => $value )
{
if ( $name [ 0 ] == '#' )
{
2009-09-27 09:59:01 +02:00
if ( $value )
2005-11-09 00:15:14 +01:00
{
$this -> db -> insert ( $this -> extra_table , array (
2009-09-27 09:59:01 +02:00
'cal_extra_value' => is_array ( $value ) ? implode ( ',' , $value ) : $value ,
2005-11-09 00:15:14 +01:00
), array (
'cal_id' => $cal_id ,
'cal_extra_name' => substr ( $name , 1 ),
2008-03-15 15:10:20 +01:00
), __LINE__ , __FILE__ , 'calendar' );
2005-11-09 00:15:14 +01:00
}
else
{
$this -> db -> delete ( $this -> extra_table , array (
'cal_id' => $cal_id ,
'cal_extra_name' => substr ( $name , 1 ),
2008-03-15 15:10:20 +01:00
), __LINE__ , __FILE__ , 'calendar' );
2006-03-29 09:01:18 +02:00
}
2005-11-09 00:15:14 +01:00
}
}
2010-06-08 18:36:55 +02:00
// updating or saving the alarms; new alarms have a temporary numeric id!
2005-11-09 00:15:14 +01:00
if ( is_array ( $event [ 'alarm' ]))
{
foreach ( $event [ 'alarm' ] as $id => $alarm )
{
2010-06-08 18:36:55 +02:00
if ( is_numeric ( $id )) unset ( $alarm [ 'id' ]); // unset the temporary id to add the alarm
2005-11-09 00:15:14 +01:00
2008-11-17 20:06:27 +01:00
if ( ! isset ( $alarm [ 'offset' ]))
{
$alarm [ 'offset' ] = $event [ 'cal_start' ] - $alarm [ 'time' ];
}
elseif ( ! isset ( $alarm [ 'time' ]))
{
$alarm [ 'time' ] = $event [ 'cal_start' ] - $alarm [ 'offset' ];
}
2010-06-08 18:36:55 +02:00
//pgoerzen: don't add an alarm in the past
if ( $event [ 'recur_type' ] != MCAL_RECUR_NONE )
2008-11-17 20:06:27 +01:00
{
2010-06-08 18:36:55 +02:00
$where = array ( 'cal_id' => $cal_id );
$where [] = 'cal_start >= ' . ( int )( time () + $alarm [ 'offset' ]);
if (( $next_occurrence = ( int ) $this -> db -> select ( $this -> dates_table , 'MIN(cal_start)' , $where , __LINE__ , __FILE__ , false , '' , 'calendar' ) -> fetchColumn ())
&& ( $time = $next_occurrence - $alarm [ 'offset' ]) > $alarm [ 'time' ])
{
$alarm [ 'time' ] = $time ;
}
2010-06-18 15:37:42 +02:00
elseif ( ! $next_occurrence )
{
continue ;
}
2010-06-08 18:36:55 +02:00
}
2005-11-09 00:15:14 +01:00
$this -> save_alarm ( $cal_id , $alarm );
}
}
2008-05-08 00:12:25 +02:00
if ( is_null ( $etag ))
{
2009-06-08 18:21:14 +02:00
$etag = $this -> db -> select ( $this -> cal_table , 'cal_etag' , array ( 'cal_id' => $cal_id ), __LINE__ , __FILE__ , false , '' , 'calendar' ) -> fetchColumn ();
2008-05-08 00:12:25 +02:00
}
2005-11-09 00:15:14 +01:00
return $cal_id ;
}
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
/**
* moves an event to an other start - and end - time taken into account the evtl . recurrences of the event ( ! )
*
* @ param int $cal_id
* @ param int $start new starttime
* @ param int $end new endtime
2009-05-05 00:39:27 +02:00
* @ param int | boolean $change_since = 0 false = new entry , > 0 time from which on the repetitions should be changed , default 0 = all
2005-11-09 00:15:14 +01:00
* @ param int $old_start = 0 old starttime or ( default ) 0 , to query it from the db
* @ param int $old_end = 0 old starttime or ( default ) 0
2009-11-04 08:57:55 +01:00
* @ todo Recalculate recurrences , if timezone changes
2009-05-05 00:39:27 +02:00
* @ return int | boolean number of moved recurrences or false on error
2005-11-09 00:15:14 +01:00
*/
2009-11-04 16:00:08 +01:00
function move ( $cal_id , $start , $end , $change_since = 0 , $old_start = 0 , $old_end = 0 )
2005-11-09 00:15:14 +01:00
{
//echo "<p>socal::move($cal_id,$start,$end,$change_since,$old_start,$old_end)</p>\n";
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
if ( ! ( int ) $cal_id ) return false ;
if ( ! $old_start )
{
2008-03-15 15:10:20 +01:00
if ( $change_since !== false ) $row = $this -> db -> select ( $this -> dates_table , 'MIN(cal_start) AS cal_start,MIN(cal_end) AS cal_end' ,
array ( 'cal_id' => $cal_id ), __LINE__ , __FILE__ , false , '' , 'calendar' ) -> fetch ();
2005-11-09 00:15:14 +01:00
// if no recurrence found, create one with the new dates
2008-03-15 15:10:20 +01:00
if ( $change_since === false || ! $row || ! $row [ 'cal_start' ] || ! $row [ 'cal_end' ])
2005-11-09 00:15:14 +01:00
{
$this -> db -> insert ( $this -> dates_table , array (
'cal_id' => $cal_id ,
'cal_start' => $start ,
'cal_end' => $end ,
2008-03-15 15:10:20 +01:00
), false , __LINE__ , __FILE__ , 'calendar' );
2005-11-09 00:15:14 +01:00
return 1 ;
}
$move_start = ( int ) ( $start - $row [ 'cal_start' ]);
$move_end = ( int ) ( $end - $row [ 'cal_end' ]);
}
else
{
$move_start = ( int ) ( $start - $old_start );
$move_end = ( int ) ( $end - $old_end );
}
2008-03-15 15:10:20 +01:00
$where = 'cal_id=' . ( int ) $cal_id ;
2005-11-09 00:15:14 +01:00
if ( $move_start )
{
// move the recur-date of the participants
$this -> db -> query ( " UPDATE $this->user_table SET cal_recur_date=cal_recur_date+ $move_start WHERE $where AND cal_recur_date " .
2009-08-09 09:51:27 +02:00
(( int ) $change_since ? '>= ' . ( int ) $change_since : '!= 0' ), __LINE__ , __FILE__ );
2005-11-09 00:15:14 +01:00
}
if ( $move_start || $move_end )
{
// move the event and it's recurrences
2009-11-04 16:00:08 +01:00
$this -> db -> query ( " UPDATE $this->dates_table SET cal_start=cal_start+ $move_start ,cal_end=cal_end+ $move_end WHERE $where " .
2008-03-15 15:10:20 +01:00
(( int ) $change_since ? ' AND cal_start >= ' . ( int ) $change_since : '' ), __LINE__ , __FILE__ );
2005-11-09 00:15:14 +01:00
}
return $this -> db -> affected_rows ();
}
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
/**
* combines user_type and user_id into a single string or integer ( for users )
*
* @ param string $user_type 1 - char type : 'u' = user , ...
2008-05-08 17:02:35 +02:00
* @ param string | int $user_id id
* @ return string | int combined id
2005-11-09 00:15:14 +01:00
*/
2009-08-06 13:29:05 +02:00
static function combine_user ( $user_type , $user_id )
2005-11-09 00:15:14 +01:00
{
if ( ! $user_type || $user_type == 'u' )
{
return ( int ) $user_id ;
}
return $user_type . $user_id ;
}
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
/**
* splits the combined user_type and user_id into a single values
*
2008-05-08 17:02:35 +02:00
* @ param string | int $uid
* @ param string & $user_type 1 - char type : 'u' = user , ...
* @ param string | int & $user_id id
2005-11-09 00:15:14 +01:00
*/
2009-08-06 13:29:05 +02:00
static function split_user ( $uid , & $user_type , & $user_id )
2005-11-09 00:15:14 +01:00
{
if ( is_numeric ( $uid ))
{
$user_type = 'u' ;
$user_id = ( int ) $uid ;
}
else
{
$user_type = $uid [ 0 ];
2008-05-08 17:02:35 +02:00
$user_id = substr ( $uid , 1 );
2005-11-09 00:15:14 +01:00
}
}
2006-03-29 09:01:18 +02:00
2009-08-06 13:29:05 +02:00
/**
* Combine status , quantity and role into one value
*
* @ param string $status
2009-10-13 10:58:54 +02:00
* @ param int $quantity = 1
* @ param string $role = 'REQ-PARTICIPANT'
2009-08-06 13:29:05 +02:00
* @ return string
*/
2009-10-13 10:58:54 +02:00
static function combine_status ( $status , $quantity = 1 , $role = 'REQ-PARTICIPANT' )
2009-08-06 13:29:05 +02:00
{
if (( int ) $quantity > 1 ) $status .= ( int ) $quantity ;
if ( $role != 'REQ-PARTICIPANT' ) $status .= $role ;
return $status ;
}
/**
* splits the combined status , quantity and role
*
* @ param string & $status I : combined value , O : status letter : U , T , A , R
* @ param int & $quantity only O : quantity
* @ param string & $role only O : role
*/
static function split_status ( & $status , & $quantity , & $role )
{
$quantity = 1 ;
$role = 'REQ-PARTICIPANT' ;
if ( strlen ( $status ) > 1 && preg_match ( '/^.([0-9]*)(.*)$/' , $status , $matches ))
{
if (( int ) $matches [ 1 ] > 0 ) $quantity = ( int ) $matches [ 1 ];
2009-10-12 21:16:42 +02:00
if ( $matches [ 2 ]) $role = $matches [ 2 ];
2009-08-06 13:29:05 +02:00
$status = $status [ 0 ];
}
2009-11-26 19:36:19 +01:00
elseif ( $status === true )
{
$status = 'U' ;
}
2009-08-06 13:29:05 +02:00
}
2005-11-09 00:15:14 +01:00
/**
* updates the participants of an event , taken into account the evtl . recurrences of the event ( ! )
2009-08-17 16:45:42 +02:00
* this method just adds new participants or removes not longer set participants
2010-03-07 00:06:43 +01:00
* this method does never overwrite existing entries ( except the 0 - recurrence and for delete )
2006-03-29 09:01:18 +02:00
*
2005-11-09 00:15:14 +01:00
* @ param int $cal_id
2009-08-04 19:14:16 +02:00
* @ param array $participants uid => status pairs
2010-03-07 00:06:43 +01:00
* @ param int | boolean $change_since = 0 , false = new event ,
* 0 = all , > 0 time from which on the repetitions should be changed
2009-08-17 16:45:42 +02:00
* @ param boolean $add_only = false
* false = add AND delete participants if needed ( full list of participants required in $participants )
* true = only add participants if needed , no participant will be deleted ( participants to check / add required in $participants )
2009-05-05 00:39:27 +02:00
* @ return int | boolean number of updated recurrences or false on error
2005-11-09 00:15:14 +01:00
*/
2009-08-17 16:45:42 +02:00
function participants ( $cal_id , $participants , $change_since = 0 , $add_only = false )
2005-11-09 00:15:14 +01:00
{
2009-11-29 15:03:45 +01:00
$recurrences = array ();
2005-11-23 15:21:20 +01:00
// remove group-invitations, they are NOT stored in the db
foreach ( $participants as $uid => $status )
{
2009-08-06 13:29:05 +02:00
if ( $status [ 0 ] == 'G' )
2005-11-23 15:21:20 +01:00
{
unset ( $participants [ $uid ]);
}
}
2005-11-09 00:15:14 +01:00
$where = array ( 'cal_id' => $cal_id );
if (( int ) $change_since )
{
2009-10-19 22:50:17 +02:00
$where [ 0 ] = '(cal_recur_date=0 OR cal_recur_date >= ' . ( int ) $change_since . ')' ;
2005-11-09 00:15:14 +01:00
}
2009-09-27 09:59:01 +02:00
2009-11-29 15:03:45 +01:00
if ( $change_since !== false )
2005-11-09 00:15:14 +01:00
{
2009-11-29 15:03:45 +01:00
// find all existing recurrences
foreach ( $this -> db -> select ( $this -> user_table , 'DISTINCT cal_recur_date' , $where , __LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
{
$recurrences [] = $row [ 'cal_recur_date' ];
}
// update existing entries
2009-08-17 16:45:42 +02:00
$existing_entries = $this -> db -> select ( $this -> user_table , 'DISTINCT cal_user_type,cal_user_id' , $where , __LINE__ , __FILE__ , false , '' , 'calendar' );
// create a full list of participants which already exist in the db
$old_participants = array ();
foreach ( $existing_entries as $row )
2005-11-09 00:15:14 +01:00
{
2009-08-17 16:45:42 +02:00
$old_participants [ self :: combine_user ( $row [ 'cal_user_type' ], $row [ 'cal_user_id' ])] = true ;
}
// tag participants which should be deleted
if ( $add_only === false )
{
$deleted = array ();
foreach ( $existing_entries as $row )
2005-11-09 00:15:14 +01:00
{
2009-08-17 16:45:42 +02:00
$uid = self :: combine_user ( $row [ 'cal_user_type' ], $row [ 'cal_user_id' ]);
// delete not longer set participants
if ( ! isset ( $participants [ $uid ]))
{
$deleted [ $row [ 'cal_user_type' ]][] = $row [ 'cal_user_id' ];
}
2005-11-09 00:15:14 +01:00
}
}
2009-08-17 16:45:42 +02:00
// only keep added participants for further steps - we do not touch existing ones
$participants = array_diff_key ( $participants , $old_participants );
// delete participants tagged for delete
if ( $add_only === false && count ( $deleted ))
2005-11-09 00:15:14 +01:00
{
$to_or = array ();
2008-03-15 15:10:20 +01:00
$table_def = $this -> db -> get_table_definitions ( 'calendar' , $this -> user_table );
2005-11-09 00:15:14 +01:00
foreach ( $deleted as $type => $ids )
{
2008-03-15 15:10:20 +01:00
$to_or [] = $this -> db -> expression ( $table_def , array (
2005-11-09 00:15:14 +01:00
'cal_user_type' => $type ,
'cal_user_id' => $ids ,
));
}
2009-10-07 06:23:42 +02:00
$where [ 1 ] = '(' . implode ( ' OR ' , $to_or ) . ')' ;
2009-10-07 01:30:05 +02:00
$this -> db -> delete ( $this -> user_table , $where , __LINE__ , __FILE__ , 'calendar' );
2009-10-07 06:23:42 +02:00
unset ( $where [ 1 ]);
2005-11-09 00:15:14 +01:00
}
}
2009-09-27 09:59:01 +02:00
2009-08-17 16:45:42 +02:00
if ( count ( $participants )) // participants which need to be added
2005-11-09 00:15:14 +01:00
{
2009-11-29 15:03:45 +01:00
if ( ! count ( $recurrences )) $recurrences [] = 0 ; // insert the default recurrence
2005-11-09 00:15:14 +01:00
2009-08-17 16:45:42 +02:00
// update participants
2005-11-09 00:15:14 +01:00
foreach ( $participants as $uid => $status )
{
2010-03-07 00:06:43 +01:00
$type = $id = $quantity = $role = null ;
2009-08-06 13:29:05 +02:00
self :: split_user ( $uid , $type , $id );
self :: split_status ( $status , $quantity , $role );
2009-08-04 19:14:16 +02:00
$set = array (
2009-08-06 13:29:05 +02:00
'cal_status' => $status ,
'cal_quantity' => $quantity ,
'cal_role' => $role ,
2009-08-04 19:14:16 +02:00
);
2005-11-09 00:15:14 +01:00
foreach ( $recurrences as $recur_date )
{
2009-08-04 19:14:16 +02:00
$this -> db -> insert ( $this -> user_table , $set , array (
2007-06-11 19:13:43 +02:00
'cal_id' => $cal_id ,
'cal_recur_date' => $recur_date ,
2005-11-09 00:15:14 +01:00
'cal_user_type' => $type ,
'cal_user_id' => $id ,
2008-03-15 15:10:20 +01:00
), __LINE__ , __FILE__ , 'calendar' );
2005-11-09 00:15:14 +01:00
}
}
}
2006-03-29 09:01:18 +02:00
return true ;
2005-11-09 00:15:14 +01:00
}
/**
* set the status of one participant for a given recurrence or for all recurrences since now ( includes recur_date = 0 )
*
* @ param int $cal_id
2006-12-25 13:16:40 +01:00
* @ param char $user_type 'u' regular user , 'r' resource , 'c' contact
2005-11-09 00:15:14 +01:00
* @ param int $user_id
2009-07-15 22:35:56 +02:00
* @ param int | char $status numeric status ( defines ) or 1 - char code : 'R' , 'U' , 'T' or 'A'
2005-11-09 00:15:14 +01:00
* @ param int $recur_date = 0 date to change , or 0 = all since now
2009-08-04 19:14:16 +02:00
* @ param string $role = null role to set if ! is_null ( $role )
2005-11-09 00:15:14 +01:00
* @ return int number of changed recurrences
*/
2009-08-04 19:14:16 +02:00
function set_status ( $cal_id , $user_type , $user_id , $status , $recur_date = 0 , $role = null )
2005-11-09 00:15:14 +01:00
{
static $status_code_short = array (
REJECTED => 'R' ,
NO_RESPONSE => 'U' ,
TENTATIVE => 'T' ,
2010-02-17 14:29:28 +01:00
ACCEPTED => 'A' ,
DELEGATED => 'D'
2005-11-09 00:15:14 +01:00
);
2009-03-24 09:06:05 +01:00
if ( ! ( int ) $cal_id || ! ( int ) $user_id && $user_type != 'e' )
{
return false ;
}
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
if ( is_numeric ( $status )) $status = $status_code_short [ $status ];
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
$where = array (
'cal_id' => $cal_id ,
'cal_user_type' => $user_type ? $user_type : 'u' ,
'cal_user_id' => $user_id ,
);
if (( int ) $recur_date )
{
$where [ 'cal_recur_date' ] = $recur_date ;
}
else
{
$where [] = '(cal_recur_date=0 OR cal_recur_date >= ' . time () . ')' ;
}
2009-08-17 16:45:42 +02:00
// check if the user has any status database entries and create the default set if needed
// a status update before having the necessary entries happens on e.g. group invitations
$this -> participants ( $cal_id , array ( self :: combine_user ( $user_type , $user_id ) => 'U' ), 0 , true );
2005-11-23 15:21:20 +01:00
if ( $status == 'G' ) // remove group invitations, as we dont store them in the db
{
2008-03-15 15:10:20 +01:00
$this -> db -> delete ( $this -> user_table , $where , __LINE__ , __FILE__ , 'calendar' );
2005-11-23 15:21:20 +01:00
}
else
{
2009-08-04 19:14:16 +02:00
$set = array ( 'cal_status' => $status );
2009-11-26 19:36:19 +01:00
if ( ! is_null ( $role ) && $role != 'REQ-PARTICIPANT' ) $set [ 'cal_role' ] = $role ;
2009-08-04 19:14:16 +02:00
$this -> db -> insert ( $this -> user_table , $set , $where , __LINE__ , __FILE__ , 'calendar' );
2005-11-23 15:21:20 +01:00
}
2009-03-24 09:06:05 +01:00
$ret = $this -> db -> affected_rows ();
2009-07-15 22:35:56 +02:00
//error_log(__METHOD__."($cal_id,$user_type,$user_id,$status,$recur_date) = $ret");
2009-08-04 19:14:16 +02:00
return $ret ;
2005-11-09 00:15:14 +01:00
}
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
/**
* creates or update a recurrence in the dates and users table
*
2006-03-29 09:01:18 +02:00
* @ param int $cal_id
2005-11-09 00:15:14 +01:00
* @ param int $start
* @ param int $end
* @ param array $participants uid => status pairs
*/
function recurrence ( $cal_id , $start , $end , $participants )
{
//echo "<p>socal::recurrence($cal_id,$start,$end,".print_r($participants,true).")</p>\n";
$this -> db -> insert ( $this -> dates_table , array (
'cal_end' => $end ,
), array (
'cal_id' => $cal_id ,
'cal_start' => $start ,
2008-03-15 15:10:20 +01:00
), __LINE__ , __FILE__ , 'calendar' );
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
foreach ( $participants as $uid => $status )
{
2005-11-23 15:21:20 +01:00
if ( $status == 'G' ) continue ; // dont save group-invitations
2009-07-15 22:35:56 +02:00
$type = '' ;
$id = null ;
2009-11-26 21:21:16 +01:00
self :: split_user ( $uid , $type , $id );
self :: split_status ( $status , $quantity , $role );
2005-11-09 00:15:14 +01:00
$this -> db -> insert ( $this -> user_table , array (
2009-11-26 19:36:19 +01:00
'cal_status' => $status ,
'cal_quantity' => $quantity ,
'cal_role' => $role
2005-11-09 00:15:14 +01:00
), array (
'cal_id' => $cal_id ,
'cal_recur_date' => $start ,
'cal_user_type' => $type ,
'cal_user_id' => $id ,
2008-03-15 15:10:20 +01:00
), __LINE__ , __FILE__ , 'calendar' );
2005-11-09 00:15:14 +01:00
}
}
/**
* Get all unfinished recuring events ( or all users ) after a given time
*
2006-03-29 09:01:18 +02:00
* @ param int $time
2005-11-09 00:15:14 +01:00
* @ return array with cal_id => max ( cal_start ) pairs
*/
function unfinished_recuring ( $time )
{
2008-03-15 15:10:20 +01:00
$ids = array ();
foreach ( $this -> db -> select ( $this -> repeats_table , " $this->repeats_table .cal_id,MAX(cal_start) AS cal_start " , array (
2005-11-09 00:15:14 +01:00
" $this->repeats_table .cal_id = $this->dates_table .cal_id " ,
'(recur_enddate = 0 OR recur_enddate IS NULL OR recur_enddate > ' . ( int ) $time . ')' ,
2008-03-15 15:10:20 +01:00
), __LINE__ , __FILE__ , false , " GROUP BY $this->repeats_table .cal_id " , 'calendar' , 0 , ',' . $this -> dates_table ) as $row )
2005-11-09 00:15:14 +01:00
{
$ids [ $row [ 'cal_id' ]] = $row [ 'cal_start' ];
}
return $ids ;
}
/**
* deletes an event incl . all recurrences , participants and alarms
*
* @ param int $cal_id
*/
function delete ( $cal_id )
{
//echo "<p>socal::delete($cal_id)</p>\n";
$this -> delete_alarms ( $cal_id );
foreach ( $this -> all_tables as $table )
{
2008-03-15 15:10:20 +01:00
$this -> db -> delete ( $table , array ( 'cal_id' => $cal_id ), __LINE__ , __FILE__ , 'calendar' );
2005-11-09 00:15:14 +01:00
}
}
2010-06-14 13:45:00 +02:00
/**
* Delete all events that were before the given date .
*
* Recurring events that finished before the date will be deleted .
* Recurring events that span the date will be ignored . Non - recurring
* events before the date will be deleted .
*
* @ param int $date
*/
function purge ( $date )
{
// Start with egw_cal, it's the easiest
2010-07-06 10:20:53 +02:00
$sql = " (SELECT egw_cal.cal_id FROM egw_cal
2010-06-14 13:45:00 +02:00
LEFT JOIN egw_cal_repeats ON
2010-07-06 10:20:53 +02:00
egw_cal_repeats . cal_id = egw_cal . cal_id
2010-07-01 17:27:37 +02:00
JOIN egw_cal_dates ON
egw_cal . cal_id = egw_cal_dates . cal_id
2010-07-06 10:20:53 +02:00
WHERE cal_end < $date AND ( egw_cal_repeats . cal_id IS NULL OR ( recur_enddate < $date AND recur_enddate != 0 ))) AS TOPROCESS " ;
2010-06-14 13:45:00 +02:00
2010-07-06 10:20:53 +02:00
// Get what we want to delete for all tables and links
2010-06-14 13:45:00 +02:00
foreach ( $this -> db -> select (
2010-07-06 10:20:53 +02:00
$sql ,
2010-06-14 13:45:00 +02:00
array ( 'cal_id' ),
2010-07-06 10:20:53 +02:00
null ,
2010-06-14 13:45:00 +02:00
__LINE__ , __FILE__ , false
2010-07-06 10:20:53 +02:00
) as $row )
2010-06-14 13:45:00 +02:00
{
2010-07-06 10:20:53 +02:00
//echo __METHOD__." About to delete".$row['cal_id']."\r\n";
foreach ( $this -> all_tables as $table )
{
$this -> db -> delete ( $table , array ( 'cal_id' => $row [ 'cal_id' ]), __LINE__ , __FILE__ , 'calendar' );
}
// handle sync
$this -> db -> query ( ' UPDATE egw_api_content_history
SET sync_deleted = NOW ()
WHERE sync_appname = \ ' calendar\ '
AND sync_contentid = '.$row[' cal_id ' ], __LINE__ , __FILE__ );
// handle links
egw_link :: unlink ( '' , 'calendar' , $row [ 'cal_id' ]);
2010-06-14 13:45:00 +02:00
}
}
2005-11-09 00:15:14 +01:00
/**
* read the alarms of a calendar - event specified by $cal_id
*
* alarm - id is a string of 'cal:' . $cal_id . ':' . $alarm_nr , it is used as the job - id too
*
* @ param int $cal_id
* @ return array of alarms with alarm - id as key
*/
function read_alarms ( $cal_id )
{
$alarms = array ();
if ( $jobs = $this -> async -> read ( 'cal:' . ( int ) $cal_id . ':%' ))
{
foreach ( $jobs as $id => $job )
{
$alarm = $job [ 'data' ]; // text, enabled
$alarm [ 'id' ] = $id ;
$alarm [ 'time' ] = $job [ 'next' ];
$alarms [ $id ] = $alarm ;
}
}
return $alarms ;
}
/**
* read a single alarm specified by it ' s $id
*
* @ param string $id alarm - id is a string of 'cal:' . $cal_id . ':' . $alarm_nr , it is used as the job - id too
* @ return array with data of the alarm
*/
function read_alarm ( $id )
{
if ( ! ( $jobs = $this -> async -> read ( $id )))
{
return False ;
}
list ( $id , $job ) = each ( $jobs );
$alarm = $job [ 'data' ]; // text, enabled
$alarm [ 'id' ] = $id ;
$alarm [ 'time' ] = $job [ 'next' ];
//echo "<p>read_alarm('$id')="; print_r($alarm); echo "</p>\n";
return $alarm ;
}
/**
* saves a new or updated alarm
*
* @ param int $cal_id Id of the calendar - entry
* @ param array $alarm array with fields : text , owner , enabled , ..
2010-06-07 19:54:29 +02:00
* @ param timestamp $now = 0 timestamp for modification of related event
2005-11-09 00:15:14 +01:00
* @ return string id of the alarm
*/
2010-06-07 19:54:29 +02:00
function save_alarm ( $cal_id , $alarm , $now = 0 )
2005-11-09 00:15:14 +01:00
{
//echo "<p>save_alarm(cal_id=$cal_id, alarm="; print_r($alarm); echo ")</p>\n";
if ( ! ( $id = $alarm [ 'id' ]))
{
$alarms = $this -> read_alarms ( $cal_id ); // find a free alarm#
$n = count ( $alarms );
do
{
$id = 'cal:' . ( int ) $cal_id . ':' . $n ;
++ $n ;
}
while ( @ isset ( $alarms [ $id ]));
}
else
{
$this -> async -> cancel_timer ( $id );
}
$alarm [ 'cal_id' ] = $cal_id ; // we need the back-reference
2008-06-10 06:22:37 +02:00
if ( ! $this -> async -> set_timer ( $alarm [ 'time' ], $id , 'calendar.calendar_boupdate.send_alarm' , $alarm ))
2005-11-09 00:15:14 +01:00
{
return False ;
}
2009-07-15 22:35:56 +02:00
// update the modification information of the related event
2010-06-07 19:54:29 +02:00
if ( ! $now ) $now = time ();
2009-07-15 22:35:56 +02:00
$modifier = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
2009-08-06 13:29:05 +02:00
$this -> db -> update ( $this -> cal_table , array ( 'cal_modified' => $now , 'cal_modifier' => $modifier ),
2009-07-15 22:35:56 +02:00
array ( 'cal_id' => $cal_id ), __LINE__ , __FILE__ , 'calendar' );
2009-08-06 13:29:05 +02:00
2005-11-09 00:15:14 +01:00
return $id ;
}
/**
* delete all alarms of a calendar - entry
*
* @ param int $cal_id Id of the calendar - entry
* @ return int number of alarms deleted
*/
function delete_alarms ( $cal_id )
{
$alarms = $this -> read_alarms ( $cal_id );
foreach ( $alarms as $id => $alarm )
{
$this -> async -> cancel_timer ( $id );
}
return count ( $alarms );
}
/**
* delete one alarms identified by its id
*
* @ param string $id alarm - id is a string of 'cal:' . $cal_id . ':' . $alarm_nr , it is used as the job - id too
2010-06-07 19:54:29 +02:00
* @ param timestamp $now = 0 timestamp for modification of related event
2005-11-09 00:15:14 +01:00
* @ return int number of alarms deleted
*/
2010-06-07 19:54:29 +02:00
function delete_alarm ( $id , $now = 0 )
2005-11-09 00:15:14 +01:00
{
2009-07-15 22:35:56 +02:00
// update the modification information of the related event
list (, $cal_id ) = explode ( ':' , $id );
2009-08-06 13:29:05 +02:00
if ( $cal_id )
{
2010-06-07 19:54:29 +02:00
if ( ! $now ) $now = time ();
2009-07-15 22:35:56 +02:00
$modifier = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
2009-08-06 13:29:05 +02:00
$this -> db -> update ( $this -> cal_table , array ( 'cal_modified' => $now , 'cal_modifier' => $modifier ),
2009-07-15 22:35:56 +02:00
array ( 'cal_id' => $cal_id ), __LINE__ , __FILE__ , 'calendar' );
}
2005-11-09 00:15:14 +01:00
return $this -> async -> cancel_timer ( $id );
}
2006-03-29 09:01:18 +02:00
2008-06-07 19:45:33 +02:00
/**
* Delete account hook
*
* @ param array | int $old_user integer old user or array with keys 'account_id' and 'new_owner' as the deleteaccount hook uses it
* @ param int $new_user = null
*/
2009-07-15 22:35:56 +02:00
function deleteaccount ( $old_user , $newuser = null )
2005-11-09 00:15:14 +01:00
{
2008-06-07 19:45:33 +02:00
if ( is_array ( $old_user ))
{
$new_user = $old_user [ 'new_owner' ];
$old_user = $old_user [ 'account_id' ];
}
2005-11-09 00:15:14 +01:00
if ( ! ( int ) $new_user )
{
2009-07-15 22:35:56 +02:00
$user_type = '' ;
$user_id = null ;
2009-11-29 15:03:45 +01:00
self :: split_user ( $old_user , $user_type , $user_id );
2006-03-29 09:01:18 +02:00
2005-11-09 00:15:14 +01:00
if ( $user_type == 'u' ) // only accounts can be owners of events
{
2008-03-15 15:10:20 +01:00
foreach ( $this -> db -> select ( $this -> cal_table , 'cal_id' , array ( 'cal_owner' => $old_user ), __LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
2005-11-09 00:15:14 +01:00
{
2008-03-15 15:10:20 +01:00
$this -> delete ( $row [ 'cal_id' ]);
2005-11-09 00:15:14 +01:00
}
}
$this -> db -> delete ( $this -> user_table , array (
'cal_user_type' => $user_type ,
'cal_user_id' => $user_id ,
2008-03-17 10:06:08 +01:00
), __LINE__ , __FILE__ , 'calendar' );
2006-03-29 09:01:18 +02:00
2006-03-21 11:05:45 +01:00
// delete calendar entries without participants (can happen if the deleted user is the only participants, but not the owner)
2008-03-15 15:10:20 +01:00
foreach ( $this -> db -> select ( $this -> cal_table , " DISTINCT $this->cal_table .cal_id " , 'cal_user_id IS NULL' , __LINE__ , __FILE__ ,
False , '' , 'calendar' , 0 , " LEFT JOIN $this->user_table ON $this->cal_table .cal_id= $this->user_table .cal_id " ) as $row )
2006-03-21 11:05:45 +01:00
{
2008-03-15 15:10:20 +01:00
$this -> delete ( $row [ 'cal_id' ]);
2006-03-21 11:05:45 +01:00
}
2005-11-09 00:15:14 +01:00
}
else
{
2008-03-15 15:10:20 +01:00
$this -> db -> update ( $this -> cal_table , array ( 'cal_owner' => $new_user ), array ( 'cal_owner' => $old_user ), __LINE__ , __FILE__ , 'calendar' );
2007-05-07 10:27:50 +02:00
// delete participation of old user, if new user is already a participant
2008-03-15 15:10:20 +01:00
$ids = array ();
foreach ( $this -> db -> select ( $this -> user_table , 'cal_id' , array ( // MySQL does NOT allow to run this as delete!
2007-05-07 10:27:50 +02:00
'cal_user_type' => 'u' ,
'cal_user_id' => $old_user ,
" cal_id IN (SELECT cal_id FROM $this->user_table other WHERE other.cal_id=cal_id AND other.cal_user_id= " . ( int ) $new_user . " AND cal_user_type='u') " ,
2008-03-15 15:10:20 +01:00
), __LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
2007-05-07 10:27:50 +02:00
{
$ids [] = $row [ 'cal_id' ];
}
if ( $ids ) $this -> db -> delete ( $this -> user_table , array (
'cal_user_type' => 'u' ,
'cal_user_id' => $old_user ,
'cal_id' => $ids ,
2008-03-15 15:10:20 +01:00
), __LINE__ , __FILE__ , 'calendar' );
2007-05-07 10:27:50 +02:00
// now change participant in the rest to contain new user instead of old user
2008-03-15 15:10:20 +01:00
$this -> db -> update ( $this -> user_table , array (
'cal_user_id' => $new_user ,
), array (
'cal_user_type' => 'u' ,
'cal_user_id' => $old_user ,
), __LINE__ , __FILE__ , 'calendar' );
2005-11-09 00:15:14 +01:00
}
}
2009-07-15 22:35:56 +02:00
/**
* get stati of all recurrences of an event for a specific participant
*
* @ param int $cal_id
2010-02-23 19:19:12 +01:00
* @ param int $uid = null participant uid ; if == null return only the recur dates
2009-11-29 15:03:45 +01:00
* @ param int $start = 0 if != 0 : startdate of the search / list ( servertime )
* @ param int $end = 0 if != 0 : enddate of the search / list ( servertime )
*
2009-07-15 22:35:56 +02:00
* @ return array recur_date => status pairs ( index 0 => main status )
*/
2010-02-23 19:19:12 +01:00
function get_recurrences ( $cal_id , $uid = null , $start = 0 , $end = 0 )
2009-07-15 22:35:56 +02:00
{
$participant_status = array ();
$where = array ( 'cal_id' => $cal_id );
2009-11-29 15:03:45 +01:00
if ( $start != 0 && $end == 0 ) $where [] = '(cal_recur_date = 0 OR cal_recur_date >= ' . ( int ) $start . ')' ;
2009-11-29 22:02:15 +01:00
if ( $start == 0 && $end != 0 ) $where [] = '(cal_recur_date = 0 OR cal_recur_date <= ' . ( int ) $end . ')' ;
2009-11-29 15:03:45 +01:00
if ( $start != 0 && $end != 0 )
{
$where [] = '(cal_recur_date = 0 OR (cal_recur_date >= ' . ( int ) $start .
' AND cal_recur_date <= ' . ( int ) $end . '))' ;
}
2009-07-15 22:35:56 +02:00
foreach ( $this -> db -> select ( $this -> user_table , 'DISTINCT cal_recur_date' , $where , __LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
{
// inititalize the array
$participant_status [ $row [ 'cal_recur_date' ]] = null ;
}
2010-02-23 19:19:12 +01:00
if ( is_null ( $uid )) return $participant_status ;
$user_type = $user_id = null ;
self :: split_user ( $uid , $user_type , $user_id );
2009-07-15 22:35:56 +02:00
$where = array (
'cal_id' => $cal_id ,
'cal_user_type' => $user_type ? $user_type : 'u' ,
'cal_user_id' => $user_id ,
);
2009-11-29 15:03:45 +01:00
if ( $start != 0 && $end == 0 ) $where [] = '(cal_recur_date = 0 OR cal_recur_date >= ' . ( int ) $start . ')' ;
2009-11-29 22:02:15 +01:00
if ( $start == 0 && $end != 0 ) $where [] = '(cal_recur_date = 0 OR cal_recur_date <= ' . ( int ) $end . ')' ;
2009-11-29 15:03:45 +01:00
if ( $start != 0 && $end != 0 )
{
$where [] = '(cal_recur_date = 0 OR (cal_recur_date >= ' . ( int ) $start .
' AND cal_recur_date <= ' . ( int ) $end . '))' ;
}
2009-11-26 21:21:16 +01:00
foreach ( $this -> db -> select ( $this -> user_table , 'cal_recur_date,cal_status,cal_quantity,cal_role' , $where ,
2009-07-15 22:35:56 +02:00
__LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
{
2009-11-26 21:21:16 +01:00
$status = self :: combine_status ( $row [ 'cal_status' ], $row [ 'cal_quantity' ], $row [ 'cal_role' ]);
$participant_status [ $row [ 'cal_recur_date' ]] = $status ;
2009-07-15 22:35:56 +02:00
}
return $participant_status ;
}
/**
* get all participants of an event
*
* @ param int $cal_id
* @ param int $recur_date = 0 gives participants of this recurrence , default 0 = all
*
* @ return array participants
*/
function get_participants ( $cal_id , $recur_date = 0 )
{
$participants = array ();
$where = array ( 'cal_id' => $cal_id );
if ( $recur_date )
{
$where [ 'cal_recur_date' ] = $recur_date ;
}
foreach ( $this -> db -> select ( $this -> user_table , 'DISTINCT cal_user_type,cal_user_id' , $where ,
__LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
{
2009-11-29 15:03:45 +01:00
$uid = self :: combine_user ( $row [ 'cal_user_type' ], $row [ 'cal_user_id' ]);
2009-07-15 22:35:56 +02:00
$id = $row [ 'cal_user_type' ] . $row [ 'cal_user_id' ];
$participants [ $id ][ 'type' ] = $row [ 'cal_user_type' ];
$participants [ $id ][ 'id' ] = $row [ 'cal_user_id' ];
$participants [ $id ][ 'uid' ] = $uid ;
}
return $participants ;
}
/**
* get all releated events
*
* @ param int $uid UID of the series
*
* @ return array of event exception ids for all events which share $uid
*/
function get_related ( $uid )
{
$where = array (
'cal_uid' => $uid ,
);
$related = array ();
foreach ( $this -> db -> select ( $this -> cal_table , 'cal_id,cal_reference' , $where ,
__LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
{
2010-01-22 20:47:32 +01:00
if ( $row [ 'cal_reference' ] != 0 )
2009-07-15 22:35:56 +02:00
{
2010-01-22 20:47:32 +01:00
// not the series master
$related [] = $row [ 'cal_id' ];
2009-07-15 22:35:56 +02:00
}
}
return $related ;
}
/**
* Gets the exception days of a given recurring event caused by
2010-01-14 18:01:30 +01:00
* irregular participant stati or timezone transitions
2009-07-15 22:35:56 +02:00
*
2009-11-19 11:13:17 +01:00
* @ param array $event Recurring Event .
* @ param string tz_id = null timezone for exports ( null for event ' s timezone )
2009-11-29 15:03:45 +01:00
* @ param int $start = 0 if != 0 : startdate of the search / list ( servertime )
2010-01-29 22:42:54 +01:00
* @ param int $end = 0 if != 0 : enddate of the search / list ( servertime )
* @ param string $filter = 'all' string filter - name : all ( not rejected ),
2010-02-17 14:29:28 +01:00
* accepted , unknown , tentative , rejected , delegated
2010-01-29 22:42:54 +01:00
* rrule return array of remote exceptions in servertime
* tz_rrule / tz_only , return ( only by ) timezone transition affected entries
* map return array of dates with no pseudo exception
* key remote occurrence date
* tz_map return array of all dates with no tz pseudo exception
2009-07-15 22:35:56 +02:00
*
* @ return array Array of exception days ( false for non - recurring events ) .
*/
2010-01-29 22:42:54 +01:00
function get_recurrence_exceptions ( $event , $tz_id = null , $start = 0 , $end = 0 , $filter = 'all' )
2009-07-15 22:35:56 +02:00
{
2010-01-29 22:42:54 +01:00
if ( ! is_array ( $event )) return false ;
2009-07-15 22:35:56 +02:00
$cal_id = ( int ) $event [ 'id' ];
2010-01-29 22:42:54 +01:00
//error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
// "($cal_id, $tz_id, $filter): " . $event['tzid']);
2009-07-15 22:35:56 +02:00
if ( ! $cal_id || $event [ 'recur_type' ] == MCAL_RECUR_NONE ) return false ;
$days = array ();
2009-11-19 11:13:17 +01:00
2010-01-29 22:42:54 +01:00
$expand_all = ( ! $this -> isWholeDay ( $event ) && $tz_id && $tz_id != $event [ 'tzid' ]);
if ( $filter == 'tz_only' && ! $expand_all ) return $days ;
$remote = in_array ( $filter , array ( 'tz_rrule' , 'rrule' ));
$egw_rrule = calendar_rrule :: event2rrule ( $event , false );
2010-02-17 14:29:28 +01:00
$egw_rrule -> current = clone $egw_rrule -> time ;
2010-01-29 22:42:54 +01:00
if ( $expand_all )
2009-11-19 11:13:17 +01:00
{
2010-01-29 22:42:54 +01:00
unset ( $event [ 'recur_excpetion' ]);
$remote_rrule = calendar_rrule :: event2rrule ( $event , false , $tz_id );
2010-02-17 14:29:28 +01:00
$remote_rrule -> current = clone $remote_rrule -> time ;
2010-01-29 22:42:54 +01:00
}
while ( $egw_rrule -> valid ())
{
2010-02-17 14:29:28 +01:00
while ( $egw_rrule -> exceptions &&
in_array ( $egw_rrule -> current -> format ( 'Ymd' ), $egw_rrule -> exceptions ))
{
if ( in_array ( $filter , array ( 'map' , 'tz_map' , 'rrule' , 'tz_rrule' )))
{
// real exception
$locts = ( int ) egw_time :: to ( $egw_rrule -> current (), 'server' );
if ( $expand_all )
{
$remts = ( int ) egw_time :: to ( $remote_rrule -> current (), 'server' );
if ( $remote )
{
$days [ $locts ] = $remts ;
}
else
{
$days [ $remts ] = $locts ;
}
}
else
{
$days [ $locts ] = $locts ;
}
}
if ( $expand_all )
{
$remote_rrule -> next_no_exception ();
}
$egw_rrule -> next_no_exception ();
if ( ! $egw_rrule -> valid ()) return $days ;
}
2010-01-29 22:42:54 +01:00
$day = $egw_rrule -> current ();
$locts = ( int ) egw_time :: to ( $day , 'server' );
$tz_exception = ( $filter == 'tz_rrule' );
//error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
// '()[EVENT Server]: ' . $day->format('Ymd\THis') . " ($locts)");
if ( $expand_all )
2009-11-19 11:13:17 +01:00
{
2010-01-29 22:42:54 +01:00
$remote_day = $remote_rrule -> current ();
$remts = ( int ) egw_time :: to ( $remote_day , 'server' );
// error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
// '()[EVENT Device]: ' . $remote_day->format('Ymd\THis') . " ($remts)");
2009-11-19 11:13:17 +01:00
}
2009-07-15 22:35:56 +02:00
2010-01-29 22:42:54 +01:00
if ( ! ( $end && $end < $locts ) && $start <= $locts )
2009-07-15 22:35:56 +02:00
{
2010-01-29 22:42:54 +01:00
// we are within the relevant time period
if ( $expand_all && $day -> format ( 'U' ) != $remote_day -> format ( 'U' ))
{
$tz_exception = true ;
if ( $filter != 'map' && $filter != 'tz_map' )
2009-07-15 22:35:56 +02:00
{
2010-01-29 22:42:54 +01:00
// timezone pseudo exception
//error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
// '() tz exception: ' . $day->format('Ymd\THis'));
if ( $remote )
2009-07-15 22:35:56 +02:00
{
2010-01-29 22:42:54 +01:00
$days [ $locts ] = $remts ;
}
else
{
$days [ $remts ] = $locts ;
}
}
}
if ( $filter != 'tz_map' && ( ! $tz_exception || $filter == 'tz_only' ) &&
$this -> status_pseudo_exception ( $event [ 'id' ], $locts , $filter ))
{
// status pseudo exception
//error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
// '() status exception: ' . $day->format('Ymd\THis'));
if ( $expand_all )
{
if ( $filter == 'tz_only' )
{
unset ( $days [ $remts ]);
}
else
{
if ( $filter != 'map' )
2010-01-14 18:01:30 +01:00
{
2010-01-29 22:42:54 +01:00
if ( $remote )
2010-01-14 18:01:30 +01:00
{
2010-01-29 22:42:54 +01:00
$days [ $locts ] = $remts ;
}
else
{
$days [ $remts ] = $locts ;
2010-01-14 18:01:30 +01:00
}
2009-11-19 11:13:17 +01:00
}
2009-07-15 22:35:56 +02:00
}
}
2010-01-29 22:42:54 +01:00
elseif ( $filter != 'map' )
{
$days [ $locts ] = $locts ;
}
}
elseif (( $filter == 'map' || filter == 'tz_map' ) &&
! $tz_exception )
{
// no pseudo exception date
if ( $expand_all )
{
$days [ $remts ] = $locts ;
}
else
{
$days [ $locts ] = $locts ;
}
}
}
2010-02-17 14:29:28 +01:00
if ( $expand_all )
2010-01-29 22:42:54 +01:00
{
2010-02-17 14:29:28 +01:00
$remote_rrule -> next_no_exception ();
2009-07-15 22:35:56 +02:00
}
2010-02-17 14:29:28 +01:00
$egw_rrule -> next_no_exception ();
2009-07-15 22:35:56 +02:00
}
return $days ;
}
2010-01-29 22:42:54 +01:00
/**
* Checks for status only pseudo exceptions
*
* @ param int $cal_id event id
* @ param int $recur_date occurrence to check
* @ param string $filter status filter criteria for user
*
* @ return boolean true , if stati don ' t match with defaults
*/
function status_pseudo_exception ( $cal_id , $recur_date , $filter )
{
static $recurrence_zero ;
static $cached_id ;
static $user ;
if ( ! isset ( $cached_id ) || $cached_id != $cal_id )
{
// get default stati
$recurrence_zero = array ();
$user = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
$where = array ( 'cal_id' => $cal_id ,
'cal_recur_date' => 0 );
foreach ( $this -> db -> select ( $this -> user_table , 'cal_user_id,cal_user_type,cal_status' , $where ,
__LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
{
switch ( $row [ 'cal_user_type' ])
{
case 'u' : // account
case 'c' : // contact
case 'e' : // email address
$uid = self :: combine_user ( $row [ 'cal_user_type' ], $row [ 'cal_user_id' ]);
$recurrence_zero [ $uid ] = $row [ 'cal_status' ];
}
}
$cached_id = $cal_id ;
}
//error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
// "($cal_id, $recur_date, $filter)[DEFAULTS]: " .
// array2string($recurrence_zero));
$participants = array ();
$where = array ( 'cal_id' => $cal_id ,
'cal_recur_date' => $recur_date );
foreach ( $this -> db -> select ( $this -> user_table , 'cal_user_id,cal_user_type,cal_status' , $where ,
__LINE__ , __FILE__ , false , '' , 'calendar' ) as $row )
{
switch ( $row [ 'cal_user_type' ])
{
case 'u' : // account
case 'c' : // contact
case 'e' : // email address
$uid = self :: combine_user ( $row [ 'cal_user_type' ], $row [ 'cal_user_id' ]);
$participants [ $uid ] = $row [ 'cal_status' ];
}
}
if ( empty ( $participants )) return false ; // occurrence does not exist at all yet
foreach ( $recurrence_zero as $uid => $status )
{
if ( $uid == $user )
{
// handle filter for current user
switch ( $filter )
{
case 'unknown' :
if ( $status != 'U' )
{
unset ( $participants [ $uid ]);
continue ;
}
break ;
case 'accepted' :
if ( $status != 'A' )
{
unset ( $participants [ $uid ]);
continue ;
}
break ;
case 'tentative' :
if ( $status != 'T' )
{
unset ( $participants [ $uid ]);
continue ;
}
break ;
case 'rejected' :
if ( $status != 'R' )
{
unset ( $participants [ $uid ]);
continue ;
}
break ;
2010-02-17 14:29:28 +01:00
case 'delegated' :
if ( $status != 'D' )
{
unset ( $participants [ $uid ]);
continue ;
}
break ;
2010-01-29 22:42:54 +01:00
case 'default' :
if ( $status == 'R' )
{
unset ( $participants [ $uid ]);
continue ;
}
break ;
default :
// All entries
}
}
if ( ! isset ( $participants [ $uid ])
|| $participants [ $uid ] != $status )
return true ;
unset ( $participants [ $uid ]);
}
return ( ! empty ( $participants ));
}
/**
* Check if the event is the whole day
*
* @ param array $event event ( all timestamps in servertime )
* @ return boolean true if whole day event within its timezone , false othwerwise
*/
function isWholeDay ( $event )
{
if ( ! isset ( $event [ 'start' ]) || ! isset ( $event [ 'end' ])) return false ;
if ( empty ( $event [ 'tzid' ]))
{
$timezone = egw_time :: $server_timezone ;
}
else
{
if ( ! isset ( self :: $tz_cache [ $event [ 'tzid' ]]))
{
self :: $tz_cache [ $event [ 'tzid' ]] = calendar_timezones :: DateTimeZone ( $event [ 'tzid' ]);
}
$timezone = self :: $tz_cache [ $event [ 'tzid' ]];
}
$start = new egw_time ( $event [ 'start' ], egw_time :: $server_timezone );
$start -> setTimezone ( $timezone );
$end = new egw_time ( $event [ 'end' ], egw_time :: $server_timezone );
$end -> setTimezone ( $timezone );
//error_log(__FILE__.'['.__LINE__.'] '.__METHOD__.
// '(): ' . $start . '-' . $end);
$start = egw_time :: to ( $start , 'array' );
$end = egw_time :: to ( $end , 'array' );
return ! $start [ 'hour' ] && ! $start [ 'minute' ] && $end [ 'hour' ] == 23 && $end [ 'minute' ] == 59 ;
}
/**
2010-02-19 18:10:15 +01:00
* Moves a datetime to the beginning of the day within timezone
2010-01-29 22:42:54 +01:00
*
* @ param egw_time & time the datetime entry
* @ param string tz_id timezone
*
* @ return DateTime
*/
2010-05-03 18:43:42 +02:00
function & startOfDay ( egw_time $time , $tz_id = null )
2010-01-29 22:42:54 +01:00
{
if ( empty ( $tz_id ))
{
$timezone = egw_time :: $server_timezone ;
}
else
{
if ( ! isset ( self :: $tz_cache [ $tz_id ]))
{
self :: $tz_cache [ $tz_id ] = calendar_timezones :: DateTimeZone ( $tz_id );
}
$timezone = self :: $tz_cache [ $tz_id ];
}
return new egw_time ( $time -> format ( 'Y-m-d 00:00:00' ), $timezone );
}
2004-11-07 15:38:00 +01:00
}