mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-24 15:48:55 +01:00
* CalDAV/calendar backported iterator from trunk to minimize resource usage
- move all filtering into SQL query in calendar_so, to be able to correctly return N rows starting from row M - re-enabling propfind iterator again for calendar (fetching events in chunks of 500), to lower memory footprint Please note: changed SQL queries used for CalDAV do not take changed participants (or status) in exceptions into account - merged: r34529, r34584, r34592, r34594, r35948
This commit is contained in:
parent
b6552771b2
commit
78b40243b7
@ -155,6 +155,10 @@ class calendar_bo
|
|||||||
* @var array $cached_holidays holidays plus birthdays (gets cached in the session for performance reasons)
|
* @var array $cached_holidays holidays plus birthdays (gets cached in the session for performance reasons)
|
||||||
*/
|
*/
|
||||||
var $cached_holidays;
|
var $cached_holidays;
|
||||||
|
/**
|
||||||
|
* @var boholiday
|
||||||
|
*/
|
||||||
|
var $holidays;
|
||||||
/**
|
/**
|
||||||
* Instance of the socal class
|
* Instance of the socal class
|
||||||
*
|
*
|
||||||
@ -445,10 +449,17 @@ class calendar_bo
|
|||||||
$this->check_move_horizont($end);
|
$this->check_move_horizont($end);
|
||||||
}
|
}
|
||||||
$daywise = !isset($params['daywise']) ? False : !!$params['daywise'];
|
$daywise = !isset($params['daywise']) ? False : !!$params['daywise'];
|
||||||
$enum_recuring = $daywise || !isset($params['enum_recuring']) || !!$params['enum_recuring'];
|
$params['enum_recuring'] = $enum_recuring = $daywise || !isset($params['enum_recuring']) || !!$params['enum_recuring'];
|
||||||
$cat_id = isset($params['cat_id']) ? $params['cat_id'] : 0;
|
$cat_id = isset($params['cat_id']) ? $params['cat_id'] : 0;
|
||||||
$filter = isset($params['filter']) ? $params['filter'] : 'all';
|
$filter = isset($params['filter']) ? $params['filter'] : 'all';
|
||||||
$offset = isset($params['offset']) && $params['offset'] !== false ? (int) $params['offset'] : false;
|
$offset = isset($params['offset']) && $params['offset'] !== false ? (int) $params['offset'] : false;
|
||||||
|
// socal::search() returns rejected group-invitations, as only the user not also the group is rejected
|
||||||
|
// as we cant remove them efficiantly in SQL, we kick them out here, but only if just one user is displayed
|
||||||
|
$users_in = (array)$params_in['users'];
|
||||||
|
$remove_rejected_by_user = !in_array($filter,array('all','rejected')) &&
|
||||||
|
count($users_in) == 1 && $users_in[0] > 0 ? $users_in[0] : null;
|
||||||
|
//error_log(__METHOD__.'('.array2string($params_in).", $sql_filter) params[users]=".array2string($params['users']).' --> remove_rejected_by_user='.array2string($remove_rejected_by_user));
|
||||||
|
|
||||||
if ($this->debug && ($this->debug > 1 || $this->debug == 'search'))
|
if ($this->debug && ($this->debug > 1 || $this->debug == 'search'))
|
||||||
{
|
{
|
||||||
$this->debug_message('bocal::search(%1) start=%2, end=%3, daywise=%4, cat_id=%5, filter=%6, query=%7, offset=%8, num_rows=%9, order=%10, sql_filter=%11)',
|
$this->debug_message('bocal::search(%1) start=%2, end=%3, daywise=%4, cat_id=%5, filter=%6, query=%7, offset=%8, num_rows=%9, order=%10, sql_filter=%11)',
|
||||||
@ -456,7 +467,7 @@ class calendar_bo
|
|||||||
}
|
}
|
||||||
// date2ts(,true) converts to server time, db2data converts again to user-time
|
// date2ts(,true) converts to server time, db2data converts again to user-time
|
||||||
$events =& $this->so->search(isset($start) ? $this->date2ts($start,true) : null,isset($end) ? $this->date2ts($end,true) : null,
|
$events =& $this->so->search(isset($start) ? $this->date2ts($start,true) : null,isset($end) ? $this->date2ts($end,true) : null,
|
||||||
$users,$cat_id,$filter,$offset,(int)$params['num_rows'],$params);
|
$users,$cat_id,$filter,$offset,(int)$params['num_rows'],$params,$remove_rejected_by_user);
|
||||||
|
|
||||||
if (isset($params['cols']))
|
if (isset($params['cols']))
|
||||||
{
|
{
|
||||||
@ -465,24 +476,9 @@ class calendar_bo
|
|||||||
$this->total = $this->so->total;
|
$this->total = $this->so->total;
|
||||||
$this->db2data($events,isset($params['date_format']) ? $params['date_format'] : 'ts');
|
$this->db2data($events,isset($params['date_format']) ? $params['date_format'] : 'ts');
|
||||||
|
|
||||||
// socal::search() returns rejected group-invitations, as only the user not also the group is rejected
|
|
||||||
// as we cant remove them efficiantly in SQL, we kick them out here, but only if just one user is displayed
|
|
||||||
$remove_rejected_by_user = !in_array($filter,array('all','rejected','owner')) && count($params['users']) == 1 ? $params['users'][0] : false;
|
|
||||||
//echo "<p align=right>remove_rejected_by_user=$remove_rejected_by_user, filter=$filter, params[users]=".print_r($param['users'])."</p>\n";
|
//echo "<p align=right>remove_rejected_by_user=$remove_rejected_by_user, filter=$filter, params[users]=".print_r($param['users'])."</p>\n";
|
||||||
foreach($events as $id => $event)
|
foreach($events as $id => $event)
|
||||||
{
|
{
|
||||||
if (isset($start) && $event['end'] < $start)
|
|
||||||
{
|
|
||||||
unset($events[$id]); // remove former events (e.g. whole day)
|
|
||||||
$this->total--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($remove_rejected_by_user && $event['participants'][$remove_rejected_by_user] == 'R')
|
|
||||||
{
|
|
||||||
unset($events[$id]); // remove the rejected event
|
|
||||||
$this->total--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ($params['enum_groups'] && $this->enum_groups($event))
|
if ($params['enum_groups'] && $this->enum_groups($event))
|
||||||
{
|
{
|
||||||
$events[$id] = $event;
|
$events[$id] = $event;
|
||||||
@ -538,29 +534,11 @@ class calendar_bo
|
|||||||
$this->debug_message('socalendar::search daywise events=%1',False,$events);
|
$this->debug_message('socalendar::search daywise events=%1',False,$events);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif(!$enum_recuring)
|
|
||||||
{
|
|
||||||
$recur_ids = array();
|
|
||||||
foreach($events as $k => $event)
|
|
||||||
{
|
|
||||||
if ($event['recur_type'] != MCAL_RECUR_NONE)
|
|
||||||
{
|
|
||||||
if (!in_array($event['id'],$recur_ids))
|
|
||||||
{
|
|
||||||
$recur_ids[] = $event['id'];
|
|
||||||
}
|
|
||||||
unset($events[$k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (count($recur_ids))
|
|
||||||
{
|
|
||||||
$events = array_merge($this->read($recur_ids,null,false,$params['date_format']),$events);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($this->debug && ($this->debug > 0 || $this->debug == 'search'))
|
if ($this->debug && ($this->debug > 0 || $this->debug == 'search'))
|
||||||
{
|
{
|
||||||
$this->debug_message('bocal::search(%1)=%2',True,$params,$events);
|
$this->debug_message('bocal::search(%1)=%2',True,$params,$events);
|
||||||
}
|
}
|
||||||
|
//error_log(__METHOD__."() returning ".count($events)." entries, total=$this->total ".function_backtrace());
|
||||||
return $events;
|
return $events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,12 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
'enum_recuring' => false,
|
'enum_recuring' => false,
|
||||||
'daywise' => false,
|
'daywise' => false,
|
||||||
'date_format' => 'server',
|
'date_format' => 'server',
|
||||||
|
'no_total' => true, // we need no total number of rows (saves extra query)
|
||||||
);
|
);
|
||||||
|
if ($this->client_shared_uid_exceptions) // do NOT return (non-virtual) exceptions
|
||||||
|
{
|
||||||
|
$filter['query'] = array('cal_reference' => 0);
|
||||||
|
}
|
||||||
|
|
||||||
if ($path == '/calendar/')
|
if ($path == '/calendar/')
|
||||||
{
|
{
|
||||||
@ -140,8 +145,7 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
}
|
}
|
||||||
if ($this->debug > 1)
|
if ($this->debug > 1)
|
||||||
{
|
{
|
||||||
error_log(__METHOD__."($path,,,$user,$id) filter=".
|
error_log(__METHOD__."($path,,,$user,$id) filter=".array2string($filter));
|
||||||
array2string($filter));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we have to return the full calendar data or just the etag's
|
// check if we have to return the full calendar data or just the etag's
|
||||||
@ -157,12 +161,12 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* disabling not working iterator
|
|
||||||
// return iterator, calling ourself to return result in chunks
|
// return iterator, calling ourself to return result in chunks
|
||||||
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
|
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Callback for profind interator
|
* Callback for profind interator
|
||||||
*
|
*
|
||||||
@ -171,15 +175,13 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
* @param array|boolean $start=false false=return all or array(start,num)
|
* @param array|boolean $start=false false=return all or array(start,num)
|
||||||
* @return array with "files" array with values for keys path and props
|
* @return array with "files" array with values for keys path and props
|
||||||
*/
|
*/
|
||||||
/* disabling not working iterator
|
|
||||||
function propfind_callback($path,array $filter,$start=false)
|
function propfind_callback($path,array $filter,$start=false)
|
||||||
{
|
{
|
||||||
*/
|
|
||||||
if ($this->debug) $starttime = microtime(true);
|
if ($this->debug) $starttime = microtime(true);
|
||||||
|
|
||||||
$calendar_data = $filter['calendar_data'];
|
$calendar_data = $filter['calendar_data'];
|
||||||
unset($filter['calendar_data']);
|
unset($filter['calendar_data']);
|
||||||
/* disabling not working iterator
|
|
||||||
$files = array();
|
$files = array();
|
||||||
|
|
||||||
if (is_array($start))
|
if (is_array($start))
|
||||||
@ -187,8 +189,6 @@ class calendar_groupdav extends groupdav_handler
|
|||||||
$filter['offset'] = $start[0];
|
$filter['offset'] = $start[0];
|
||||||
$filter['num_rows'] = $start[1];
|
$filter['num_rows'] = $start[1];
|
||||||
}
|
}
|
||||||
error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($filter));
|
|
||||||
*/
|
|
||||||
$events =& $this->bo->search($filter);
|
$events =& $this->bo->search($filter);
|
||||||
if ($events)
|
if ($events)
|
||||||
{
|
{
|
||||||
@ -197,6 +197,7 @@ error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($f
|
|||||||
{
|
{
|
||||||
if ($this->client_shared_uid_exceptions && $event['reference'])
|
if ($this->client_shared_uid_exceptions && $event['reference'])
|
||||||
{
|
{
|
||||||
|
throw new egw_exception_assertion_failed(__METHOD__."() event=".array2string($event));
|
||||||
// this exception will be handled with the series master
|
// this exception will be handled with the series master
|
||||||
unset($events[$k]);
|
unset($events[$k]);
|
||||||
continue;
|
continue;
|
||||||
@ -228,10 +229,7 @@ error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($f
|
|||||||
{
|
{
|
||||||
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
|
$props[] = HTTP_WebDAV_Server::mkprop('getcontentlength', ''); // expensive to calculate and no CalDAV client uses it
|
||||||
}
|
}
|
||||||
/* disabling not working iterator
|
|
||||||
$files[] = array(
|
$files[] = array(
|
||||||
*/
|
|
||||||
$files['files'][] = array(
|
|
||||||
'path' => $path.$this->get_path($event),
|
'path' => $path.$this->get_path($event),
|
||||||
'props' => $props,
|
'props' => $props,
|
||||||
);
|
);
|
||||||
@ -242,10 +240,7 @@ error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($f
|
|||||||
error_log(__METHOD__."($path) took ".(microtime(true) - $starttime).
|
error_log(__METHOD__."($path) took ".(microtime(true) - $starttime).
|
||||||
' to return '.count($files['files']).' items');
|
' to return '.count($files['files']).' items');
|
||||||
}
|
}
|
||||||
/* disabling not working iterator
|
|
||||||
return $files;
|
return $files;
|
||||||
*/
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,7 +98,6 @@ class calendar_so
|
|||||||
*/
|
*/
|
||||||
protected static $tz_cache = array();
|
protected static $tz_cache = array();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor of the socal class
|
* Constructor of the socal class
|
||||||
*/
|
*/
|
||||||
@ -373,17 +372,18 @@ class calendar_so
|
|||||||
* @param string $params['append'] SQL to append to the query before $order, eg. for a GROUP BY clause
|
* @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['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!
|
* @param array $params['users'] raw parameter as passed to calendar_bo::search() no memberships resolved!
|
||||||
|
* @param int $remove_rejected_by_user=null add join to remove entry, if given user has rejected it
|
||||||
* @return array of cal_ids, or false if error in the parameters
|
* @return array of cal_ids, or false if error in the parameters
|
||||||
*
|
*
|
||||||
* ToDo: search custom-fields too
|
* ToDo: search custom-fields too
|
||||||
*/
|
*/
|
||||||
function &search($start,$end,$users,$cat_id=0,$filter='all',$offset=False,$num_rows=0,array $params=array())
|
function &search($start,$end,$users,$cat_id=0,$filter='all',$offset=False,$num_rows=0,array $params=array(),$remove_rejected_by_user=null)
|
||||||
{
|
{
|
||||||
//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());
|
//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());
|
||||||
|
|
||||||
$cols = self::get_columns('calendar', $this->cal_table);
|
$cols = self::get_columns('calendar', $this->cal_table);
|
||||||
$cols[0] = $this->db->to_varchar($this->cal_table.'.cal_id');
|
$cols[0] = $this->db->to_varchar($this->cal_table.'.cal_id');
|
||||||
$cols = isset($params['cols']) ? $params['cols'] : "$this->repeats_table.recur_type,$this->repeats_table.recur_enddate,$this->repeats_table.recur_interval,$this->repeats_table.recur_data,$this->repeats_table.recur_exception,".implode(',',$cols).",cal_start,cal_end,cal_recur_date";
|
$cols = isset($params['cols']) ? $params['cols'] : "$this->repeats_table.recur_type,$this->repeats_table.recur_enddate,$this->repeats_table.recur_interval,$this->repeats_table.recur_data,$this->repeats_table.recur_exception,".implode(',',$cols).",cal_start,cal_end,$this->user_table.cal_recur_date";
|
||||||
|
|
||||||
$where = array();
|
$where = array();
|
||||||
if (is_array($params['query']))
|
if (is_array($params['query']))
|
||||||
@ -423,7 +423,8 @@ class calendar_so
|
|||||||
$users_by_type[$user[0]][] = (int) substr($user,1);
|
$users_by_type[$user[0]][] = (int) substr($user,1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$to_or = $user_or = $owner_or = array();
|
$to_or = $user_or = array();
|
||||||
|
$owner_or = null;
|
||||||
$useUnionQuery = $this->db->capabilities['distinct_on_text'] && $this->db->capabilities['union'];
|
$useUnionQuery = $this->db->capabilities['distinct_on_text'] && $this->db->capabilities['union'];
|
||||||
$table_def = $this->db->get_table_definitions('calendar',$this->user_table);
|
$table_def = $this->db->get_table_definitions('calendar',$this->user_table);
|
||||||
foreach($users_by_type as $type => $ids)
|
foreach($users_by_type as $type => $ids)
|
||||||
@ -431,20 +432,22 @@ class calendar_so
|
|||||||
// 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
|
// 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)
|
if ($useUnionQuery)
|
||||||
{
|
{
|
||||||
$user_or[] = $this->db->expression($table_def,array(
|
$user_or[] = $this->db->expression($table_def,$this->user_table.'.',array(
|
||||||
'cal_user_type' => $type,
|
'cal_user_type' => $type,
|
||||||
|
),' AND '.$this->user_table.'.',array(
|
||||||
'cal_user_id' => $ids,
|
'cal_user_id' => $ids,
|
||||||
));
|
));
|
||||||
if ($type == 'u' && ($filter == 'owner'))
|
if ($type == 'u' && $filter == 'owner')
|
||||||
{
|
{
|
||||||
$cal_table_def = $this->db->get_table_definitions('calendar',$this->cal_table);
|
$cal_table_def = $this->db->get_table_definitions('calendar',$this->cal_table);
|
||||||
$owner_or[] = $this->db->expression($cal_table_def,array('cal_owner' => $ids));
|
$owner_or = $this->db->expression($cal_table_def,array('cal_owner' => $ids));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$to_or[] = $this->db->expression($table_def,array(
|
$to_or[] = $this->db->expression($table_def,$this->user_table.'.',array(
|
||||||
'cal_user_type' => $type,
|
'cal_user_type' => $type,
|
||||||
|
),' AND '.$this->user_table.'.',array(
|
||||||
'cal_user_id' => $ids,
|
'cal_user_id' => $ids,
|
||||||
));
|
));
|
||||||
if ($type == 'u' && ($filter == 'owner'))
|
if ($type == 'u' && ($filter == 'owner'))
|
||||||
@ -465,24 +468,24 @@ class calendar_so
|
|||||||
{
|
{
|
||||||
case 'showonlypublic':
|
case 'showonlypublic':
|
||||||
$where['cal_public'] = 1;
|
$where['cal_public'] = 1;
|
||||||
$where[] = "cal_status != 'R'"; break;
|
$where[] = "$this->user_table.cal_status != 'R'"; break;
|
||||||
case 'deleted':
|
case 'deleted':
|
||||||
$where['cal_deleted'] = true; break;
|
$where['cal_deleted'] = true; break;
|
||||||
case 'unknown':
|
case 'unknown':
|
||||||
$where[] = "cal_status='U'"; break;
|
$where[] = "$this->user_table.cal_status='U'"; break;
|
||||||
case 'accepted':
|
case 'accepted':
|
||||||
$where[] = "cal_status='A'"; break;
|
$where[] = "$this->user_table.cal_status='A'"; break;
|
||||||
case 'tentative':
|
case 'tentative':
|
||||||
$where[] = "cal_status='T'"; break;
|
$where[] = "$this->user_table.cal_status='T'"; break;
|
||||||
case 'rejected':
|
case 'rejected':
|
||||||
$where[] = "cal_status='R'"; break;
|
$where[] = "$this->user_table.cal_status='R'"; break;
|
||||||
case 'delegated':
|
case 'delegated':
|
||||||
$where[] = "cal_status='D'"; break;
|
$where[] = "$this->user_table.cal_status='D'"; break;
|
||||||
case 'all':
|
case 'all':
|
||||||
case 'owner':
|
case 'owner':
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$where[] = "cal_status != 'R'";
|
$where[] = "$this->user_table.cal_status != 'R'";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -490,11 +493,44 @@ class calendar_so
|
|||||||
{
|
{
|
||||||
$where[] = $this->cat_filter($cat_id);
|
$where[] = $this->cat_filter($cat_id);
|
||||||
}
|
}
|
||||||
if ($start) $where[] = (int)$start.' < cal_end';
|
if ($start)
|
||||||
|
{
|
||||||
|
if ($params['enum_recuring'])
|
||||||
|
{
|
||||||
|
$where[] = (int)$start.' < cal_end';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we check recur_endate!=0, because it can be NULL, 0 or !=0 !!!
|
||||||
|
$where[] = (int)$start.' < (CASE WHEN recur_type IS NULL THEN cal_end ELSE (CASE WHEN recur_enddate!=0 THEN recur_enddate ELSE 9999999999 END) END)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if not enum recuring events, we have to use minimum start- AND end-dates, otherwise we get more then one event per cal_id!
|
||||||
|
if (!$params['enum_recuring'])
|
||||||
|
{
|
||||||
|
$where[] = "$this->user_table.cal_recur_date=0";
|
||||||
|
$group_by = 'GROUP BY '.str_replace(array('cal_start,','cal_end,'),'',implode(', ',(array)$cols));
|
||||||
|
$cols = str_replace(array('cal_start','cal_end'),array('MIN(cal_start) AS cal_start','MIN(cal_end) AS cal_end'),$cols);
|
||||||
|
}
|
||||||
if ($end) $where[] = 'cal_start < '.(int)$end;
|
if ($end) $where[] = 'cal_start < '.(int)$end;
|
||||||
|
|
||||||
if (!preg_match('/^[a-z_ ,]+$/i',$params['order'])) $params['order'] = 'cal_start'; // gard against SQL injection
|
if (!preg_match('/^[a-z_ ,c]+$/i',$params['order'])) $params['order'] = 'cal_start'; // gard against SQL injection
|
||||||
|
|
||||||
|
if ($remove_rejected_by_user)
|
||||||
|
{
|
||||||
|
$rejected_by_user_join = "LEFT JOIN $this->user_table rejected_by_user".
|
||||||
|
" ON $this->cal_table.cal_id=rejected_by_user.cal_id".
|
||||||
|
" AND rejected_by_user.cal_user_type='u'".
|
||||||
|
" AND rejected_by_user.cal_user_id=".$this->db->quote($remove_rejected_by_user).
|
||||||
|
" AND (recur_type IS NULL AND rejected_by_user.cal_recur_date=0 OR cal_start=rejected_by_user.cal_recur_date)";
|
||||||
|
$or_required = array(
|
||||||
|
'rejected_by_user.cal_status IS NULL',
|
||||||
|
"rejected_by_user.cal_status!='R'",
|
||||||
|
);
|
||||||
|
if ($filter == 'owner') $or_required[] = 'cal_owner='.(int)$remove_rejected_by_user;
|
||||||
|
$where[] = '('.implode(' OR ',$or_required).')';
|
||||||
|
}
|
||||||
|
//$starttime = microtime(true);
|
||||||
if ($useUnionQuery)
|
if ($useUnionQuery)
|
||||||
{
|
{
|
||||||
// allow apps to supply participants and/or icons
|
// allow apps to supply participants and/or icons
|
||||||
@ -503,89 +539,72 @@ class calendar_so
|
|||||||
// changed the original OR in the query into a union, to speed up the query execution under MySQL 5
|
// changed the original OR in the query into a union, to speed up the query execution under MySQL 5
|
||||||
$select = array(
|
$select = array(
|
||||||
'table' => $this->cal_table,
|
'table' => $this->cal_table,
|
||||||
'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",
|
'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 $rejected_by_user_join",
|
||||||
'cols' => $cols,
|
'cols' => $cols,
|
||||||
'where' => $where,
|
'where' => $where,
|
||||||
'app' => 'calendar',
|
'app' => 'calendar',
|
||||||
'append'=> $params['append'],
|
'append'=> $params['append'].' '.$group_by,
|
||||||
);
|
);
|
||||||
|
$selects = array();
|
||||||
// we check if there are parts to use for the construction of our UNION query,
|
// we check if there are parts to use for the construction of our UNION query,
|
||||||
// as replace the OR by construction of a suitable UNION for performance reasons
|
// as replace the OR by construction of a suitable UNION for performance reasons
|
||||||
if (!empty($owner_or)||!empty($user_or))
|
if ($owner_or || $user_or)
|
||||||
{
|
{
|
||||||
if (!empty($owner_or) && !empty($user_or))
|
foreach($user_or as $user_sql)
|
||||||
{
|
{
|
||||||
// if the query is to be filtered by owner OR user we need 4 selects for the union
|
$selects[] = $select;
|
||||||
//_debug_array($owner_or);
|
$selects[count($selects)-1]['where'][] = $user_sql;
|
||||||
$selects = array();
|
if ($params['enum_recuring'])
|
||||||
foreach(array_keys($user_or) as $key)
|
|
||||||
{
|
{
|
||||||
|
$selects[count($selects)-1]['where'][] = "recur_type IS NULL AND $this->user_table.cal_recur_date=0";
|
||||||
$selects[] = $select;
|
$selects[] = $select;
|
||||||
$selects[count($selects)-1]['where'][] = $user_or[$key];
|
$selects[count($selects)-1]['where'][] = $user_sql;
|
||||||
$selects[count($selects)-1]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
|
$selects[count($selects)-1]['where'][] = "$this->user_table.cal_recur_date=cal_start";
|
||||||
$selects[] = $select;
|
|
||||||
$selects[count($selects)-1]['where'][] = $user_or[$key];
|
|
||||||
$selects[count($selects)-1]['where'][] = 'cal_recur_date=cal_start';
|
|
||||||
}
|
}
|
||||||
$selects[] = $select;
|
|
||||||
$selects[count($selects)-1]['where'][] = $owner_or;
|
|
||||||
$selects[count($selects)-1]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
|
|
||||||
$selects[] = $select;
|
|
||||||
$selects[count($selects)-1]['where'][] = $owner_or;
|
|
||||||
$selects[count($selects)-1]['where'][] = 'cal_recur_date=cal_start';
|
|
||||||
}
|
}
|
||||||
else
|
// if the query is to be filtered by owner we need to add more selects for the union
|
||||||
|
if ($owner_or)
|
||||||
{
|
{
|
||||||
// if the query is to be filtered only by user we need 2 selects for the union
|
$selects[] = $select;
|
||||||
$selects = array();
|
$selects[count($selects)-1]['where'][] = $owner_or;
|
||||||
foreach(array_keys($user_or) as $key)
|
if ($params['enum_recuring'])
|
||||||
{
|
{
|
||||||
|
$selects[count($selects)-1]['where'][] = "recur_type IS NULL AND $this->user_table.cal_recur_date=0";
|
||||||
$selects[] = $select;
|
$selects[] = $select;
|
||||||
$selects[count($selects)-1]['where'][] = $user_or[$key];
|
$selects[count($selects)-1]['where'][] = $owner_or;
|
||||||
$selects[count($selects)-1]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
|
$selects[count($selects)-1]['where'][] = "$this->user_table.cal_recur_date=cal_start";
|
||||||
$selects[] = $select;
|
|
||||||
$selects[count($selects)-1]['where'][] = $user_or[$key];
|
|
||||||
$selects[count($selects)-1]['where'][] = 'cal_recur_date=cal_start';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// if the query is to be filtered by neither by user nor owner (should not happen?) we need 2 selects for the union
|
// 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[] = $select;
|
||||||
$selects[0]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
|
if ($params['enum_recuring'])
|
||||||
$selects[1]['where'][] = 'cal_recur_date=cal_start';
|
{
|
||||||
|
$selects[count($selects)-1]['where'][] = "recur_type IS NULL AND $this->user_table.cal_recur_date=0";
|
||||||
|
$selects[] = $select;
|
||||||
|
$selects[count($selects)-1]['where'][] = "$this->user_table.cal_recur_date=cal_start";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (is_numeric($offset)) // get the total too
|
if (is_numeric($offset) && !$params['no_total']) // get the total too
|
||||||
{
|
{
|
||||||
|
$save_selects = $selects;
|
||||||
// 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)
|
// 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)
|
||||||
$countSelects = count($selects);
|
|
||||||
foreach(array_keys($selects) as $key)
|
foreach(array_keys($selects) as $key)
|
||||||
{
|
{
|
||||||
$selects[$key]['cols'] = "DISTINCT $this->repeats_table.recur_type,$this->repeats_table.recur_enddate,$this->repeats_table.recur_interval,$this->repeats_table.recur_data,$this->repeats_table.recur_exception,".$this->db->to_varchar($this->cal_table.'.cal_id').",cal_start,cal_end,cal_recur_date";
|
$selects[$key]['cols'] = "DISTINCT $this->repeats_table.recur_type,$this->repeats_table.recur_enddate,$this->repeats_table.recur_interval,$this->repeats_table.recur_data,$this->repeats_table.recur_exception,".$this->db->to_varchar($this->cal_table.'.cal_id').",cal_start,cal_end,$this->user_table.cal_recur_date";
|
||||||
//$selects[0]['cols'] = $selects[1]['cols'] = "DISTINCT $this->repeats_table.*,$this->cal_table.cal_id,cal_start,cal_end,cal_recur_date";
|
if (!$params['enum_recuring'])
|
||||||
|
{
|
||||||
|
$selects[$key]['cols'] = str_replace('cal_start','MIN(cal_start) AS cal_start',$selects[$key]['cols']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!isset($param['cols'])) self::get_union_selects($selects,$start,$end,$users,$cat_id,$filter,$params['query'],$params['users']);
|
if (!isset($param['cols'])) self::get_union_selects($selects,$start,$end,$users,$cat_id,$filter,$params['query'],$params['users']);
|
||||||
|
|
||||||
$this->total = $this->db->union($selects,__LINE__,__FILE__)->NumRows();
|
$this->total = $this->db->union($selects,__LINE__,__FILE__)->NumRows();
|
||||||
$i = 0;
|
|
||||||
foreach(array_keys($selects) as $key)
|
|
||||||
{
|
|
||||||
if ($i >= $countSelects) continue;
|
|
||||||
$i++;
|
|
||||||
$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];
|
|
||||||
}
|
|
||||||
|
|
||||||
$selects = $selections;
|
// restore original cols / selects
|
||||||
|
$selects = $save_selects; unset($save_selects);
|
||||||
}
|
}
|
||||||
if (!isset($param['cols'])) self::get_union_selects($selects,$start,$end,$users,$cat_id,$filter,$params['query'],$params['users']);
|
if (!isset($param['cols'])) self::get_union_selects($selects,$start,$end,$users,$cat_id,$filter,$params['query'],$params['users']);
|
||||||
|
|
||||||
@ -593,7 +612,7 @@ class calendar_so
|
|||||||
}
|
}
|
||||||
else // MsSQL oder MySQL 3.23
|
else // MsSQL oder MySQL 3.23
|
||||||
{
|
{
|
||||||
$where[] = '(recur_type IS NULL AND cal_recur_date=0 OR cal_recur_date=cal_start)';
|
$where[] = "(recur_type IS NULL AND $this->user_table.cal_recur_date=0 OR $this->user_table.cal_recur_date=cal_start)";
|
||||||
|
|
||||||
//_debug_array($where);
|
//_debug_array($where);
|
||||||
if (is_numeric($offset)) // get the total too
|
if (is_numeric($offset)) // get the total too
|
||||||
@ -601,12 +620,13 @@ class calendar_so
|
|||||||
// 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)
|
// 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)
|
||||||
$this->total = $this->db->select($this->cal_table,"DISTINCT $this->repeats_table.*,$this->cal_table.cal_id,cal_start,cal_end,cal_recur_date",
|
$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,
|
$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();
|
"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 $rejected_by_user_join LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id")->NumRows();
|
||||||
}
|
}
|
||||||
$rs = $this->db->select($this->cal_table,($this->db->capabilities['distinct_on_text'] ? 'DISTINCT ' : '').$cols,
|
$rs = $this->db->select($this->cal_table,($this->db->capabilities['distinct_on_text'] ? 'DISTINCT ' : '').$cols,
|
||||||
$where,__LINE__,__FILE__,$offset,$params['append'].' ORDER BY '.$params['order'],'calendar',$num_rows,
|
$where,__LINE__,__FILE__,$offset,$params['append'].' ORDER BY '.$params['order'],'calendar',$num_rows,
|
||||||
"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");
|
"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 $rejected_by_user_join LEFT JOIN $this->repeats_table ON $this->cal_table.cal_id=$this->repeats_table.cal_id");
|
||||||
}
|
}
|
||||||
|
//error_log(__METHOD__."() useUnionQuery=$useUnionQuery --> query took ".(microtime(true)-$starttime));
|
||||||
if (isset($params['cols']))
|
if (isset($params['cols']))
|
||||||
{
|
{
|
||||||
return $rs; // if colums are specified we return the recordset / iterator
|
return $rs; // if colums are specified we return the recordset / iterator
|
||||||
@ -651,7 +671,7 @@ class calendar_so
|
|||||||
foreach($this->db->select($utcal_id_view,'*',array(
|
foreach($this->db->select($utcal_id_view,'*',array(
|
||||||
//'cal_id' => array_unique($ids),
|
//'cal_id' => array_unique($ids),
|
||||||
'cal_recur_date' => $recur_dates,
|
'cal_recur_date' => $recur_dates,
|
||||||
),__LINE__,__FILE__,false,'ORDER BY cal_id,cal_user_type DESC,'.self::STATUS_SORT,'calendar',$num_rows=0,$join='',
|
),__LINE__,__FILE__,false,'ORDER BY cal_id,cal_user_type DESC,'.self::STATUS_SORT,'calendar',$num_rows,$join='',
|
||||||
$this->db->get_table_definitions('calendar',$this->user_table)) as $row) // DESC puts users before resources and contacts
|
$this->db->get_table_definitions('calendar',$this->user_table)) as $row) // DESC puts users before resources and contacts
|
||||||
{
|
{
|
||||||
$id = $row['cal_id'];
|
$id = $row['cal_id'];
|
||||||
@ -715,6 +735,7 @@ class calendar_so
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//echo "<p>socal::search\n"; _debug_array($events);
|
//echo "<p>socal::search\n"; _debug_array($events);
|
||||||
|
//error_log(__METHOD__."(,filter=".array2string($params['query']).",offset=$offset, num_rows=$num_rows) returning ".count($events)." entries".($offset!==false?" total=$this->total":'').' '.function_backtrace());
|
||||||
return $events;
|
return $events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,16 +460,15 @@ class groupdav_propfind_iterator implements Iterator
|
|||||||
*
|
*
|
||||||
* @param groupdav_handler $handler
|
* @param groupdav_handler $handler
|
||||||
* @param array $filter filter for propfind call
|
* @param array $filter filter for propfind call
|
||||||
* @param array $files=null extra files/responses to return too
|
* @param array $files=array() extra files/responses to return too
|
||||||
*/
|
*/
|
||||||
public function __construct(groupdav_handler $handler, $path, array $filter,array &$files=null)
|
public function __construct(groupdav_handler $handler, $path, array $filter,array &$files=array())
|
||||||
{
|
{
|
||||||
if ($this->debug) error_log(__METHOD__."('$path', ".array2string($filter).",)");
|
if ($this->debug) error_log(__METHOD__."('$path', ".array2string($filter).",)");
|
||||||
$this->path = $path;
|
$this->path = $path;
|
||||||
$this->handler = $handler;
|
$this->handler = $handler;
|
||||||
$this->filter = $filter;
|
$this->filter = $filter;
|
||||||
$this->files = $files;
|
$this->files = $this->common_files = $files;
|
||||||
$this->common_files = $files;
|
|
||||||
reset($this->files);
|
reset($this->files);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,6 +506,12 @@ class groupdav_propfind_iterator implements Iterator
|
|||||||
if ($this->debug) error_log(__METHOD__."() returning TRUE");
|
if ($this->debug) error_log(__METHOD__."() returning TRUE");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// check if previous query gave less then CHUNK_SIZE entries --> we're done
|
||||||
|
if ($this->start && count($this->files) < self::CHUNK_SIZE)
|
||||||
|
{
|
||||||
|
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// try query further files via propfind callback of handler and store result in $this->files
|
// try query further files via propfind callback of handler and store result in $this->files
|
||||||
$this->files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
|
$this->files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
|
||||||
if (!is_array($this->files) || !($entries = count($this->files)))
|
if (!is_array($this->files) || !($entries = count($this->files)))
|
||||||
@ -514,10 +519,10 @@ class groupdav_propfind_iterator implements Iterator
|
|||||||
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
|
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
|
||||||
return false; // no further entries
|
return false; // no further entries
|
||||||
}
|
}
|
||||||
$this->start += $entries;
|
$this->start += self::CHUNK_SIZE;
|
||||||
reset($this->files);
|
reset($this->files);
|
||||||
|
|
||||||
if ($this->debug) error_log(__METHOD__."() returning ".array2string(current($this->files) !== false));
|
if ($this->debug) error_log(__METHOD__."() this->start=$this->start, entries=$entries, count(this->files)=".count($this->files)." returning ".array2string(current($this->files) !== false));
|
||||||
|
|
||||||
return current($this->files) !== false;
|
return current($this->files) !== false;
|
||||||
}
|
}
|
||||||
@ -529,11 +534,8 @@ class groupdav_propfind_iterator implements Iterator
|
|||||||
{
|
{
|
||||||
if ($this->debug) error_log(__METHOD__."()");
|
if ($this->debug) error_log(__METHOD__."()");
|
||||||
|
|
||||||
// query first set of files via propfind callback of handler and store result in $this->files
|
|
||||||
$this->start = 0;
|
$this->start = 0;
|
||||||
$files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
|
$this->files = $this->common_files;
|
||||||
$this->files = array_merge($this->common_files, $files);
|
|
||||||
$this->start += self::CHUNK_SIZE;
|
|
||||||
reset($this->files);
|
reset($this->files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user