* 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:
Ralf Becker 2011-08-03 16:53:22 +00:00
parent b6552771b2
commit 78b40243b7
4 changed files with 131 additions and 135 deletions

View File

@ -155,6 +155,10 @@ class calendar_bo
* @var array $cached_holidays holidays plus birthdays (gets cached in the session for performance reasons)
*/
var $cached_holidays;
/**
* @var boholiday
*/
var $holidays;
/**
* Instance of the socal class
*
@ -445,10 +449,17 @@ class calendar_bo
$this->check_move_horizont($end);
}
$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;
$filter = isset($params['filter']) ? $params['filter'] : 'all';
$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'))
{
$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
$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']))
{
@ -465,24 +476,9 @@ class calendar_bo
$this->total = $this->so->total;
$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";
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))
{
$events[$id] = $event;
@ -538,29 +534,11 @@ class calendar_bo
$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'))
{
$this->debug_message('bocal::search(%1)=%2',True,$params,$events);
}
//error_log(__METHOD__."() returning ".count($events)." entries, total=$this->total ".function_backtrace());
return $events;
}

View File

@ -122,7 +122,12 @@ class calendar_groupdav extends groupdav_handler
'enum_recuring' => false,
'daywise' => false,
'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/')
{
@ -140,8 +145,7 @@ class calendar_groupdav extends groupdav_handler
}
if ($this->debug > 1)
{
error_log(__METHOD__."($path,,,$user,$id) filter=".
array2string($filter));
error_log(__METHOD__."($path,,,$user,$id) filter=".array2string($filter));
}
// 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
$files['files'] = new groupdav_propfind_iterator($this,$path,$filter,$files['files']);
return true;
}
*/
/**
* 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)
* @return array with "files" array with values for keys path and props
*/
/* disabling not working iterator
function propfind_callback($path,array $filter,$start=false)
{
*/
if ($this->debug) $starttime = microtime(true);
$calendar_data = $filter['calendar_data'];
unset($filter['calendar_data']);
/* disabling not working iterator
$files = array();
if (is_array($start))
@ -187,8 +189,6 @@ class calendar_groupdav extends groupdav_handler
$filter['offset'] = $start[0];
$filter['num_rows'] = $start[1];
}
error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($filter));
*/
$events =& $this->bo->search($filter);
if ($events)
{
@ -197,6 +197,7 @@ error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($f
{
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
unset($events[$k]);
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
}
/* disabling not working iterator
$files[] = array(
*/
$files['files'][] = array(
'path' => $path.$this->get_path($event),
'props' => $props,
);
@ -242,10 +240,7 @@ error_log(__METHOD__."($path,,".array2string($start).") filter=".array2string($f
error_log(__METHOD__."($path) took ".(microtime(true) - $starttime).
' to return '.count($files['files']).' items');
}
/* disabling not working iterator
return $files;
*/
return true;
}
/**

View File

@ -98,7 +98,6 @@ class calendar_so
*/
protected static $tz_cache = array();
/**
* 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 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 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
*
* 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[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();
if (is_array($params['query']))
@ -423,7 +423,8 @@ class calendar_so
$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'];
$table_def = $this->db->get_table_definitions('calendar',$this->user_table);
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
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,
),' AND '.$this->user_table.'.',array(
'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);
$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
{
$to_or[] = $this->db->expression($table_def,array(
$to_or[] = $this->db->expression($table_def,$this->user_table.'.',array(
'cal_user_type' => $type,
),' AND '.$this->user_table.'.',array(
'cal_user_id' => $ids,
));
if ($type == 'u' && ($filter == 'owner'))
@ -465,24 +468,24 @@ class calendar_so
{
case 'showonlypublic':
$where['cal_public'] = 1;
$where[] = "cal_status != 'R'"; break;
$where[] = "$this->user_table.cal_status != 'R'"; break;
case 'deleted':
$where['cal_deleted'] = true; break;
case 'unknown':
$where[] = "cal_status='U'"; break;
$where[] = "$this->user_table.cal_status='U'"; break;
case 'accepted':
$where[] = "cal_status='A'"; break;
$where[] = "$this->user_table.cal_status='A'"; break;
case 'tentative':
$where[] = "cal_status='T'"; break;
$where[] = "$this->user_table.cal_status='T'"; break;
case 'rejected':
$where[] = "cal_status='R'"; break;
$where[] = "$this->user_table.cal_status='R'"; break;
case 'delegated':
$where[] = "cal_status='D'"; break;
$where[] = "$this->user_table.cal_status='D'"; break;
case 'all':
case 'owner':
break;
default:
$where[] = "cal_status != 'R'";
$where[] = "$this->user_table.cal_status != 'R'";
break;
}
}
@ -490,11 +493,44 @@ class calendar_so
{
$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 (!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)
{
// 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
$select = array(
'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,
'where' => $where,
'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,
// 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
//_debug_array($owner_or);
$selects = array();
foreach(array_keys($user_or) as $key)
$selects[] = $select;
$selects[count($selects)-1]['where'][] = $user_sql;
if ($params['enum_recuring'])
{
$selects[count($selects)-1]['where'][] = "recur_type IS NULL AND $this->user_table.cal_recur_date=0";
$selects[] = $select;
$selects[count($selects)-1]['where'][] = $user_or[$key];
$selects[count($selects)-1]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
$selects[] = $select;
$selects[count($selects)-1]['where'][] = $user_or[$key];
$selects[count($selects)-1]['where'][] = 'cal_recur_date=cal_start';
$selects[count($selects)-1]['where'][] = $user_sql;
$selects[count($selects)-1]['where'][] = "$this->user_table.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 = array();
foreach(array_keys($user_or) as $key)
$selects[] = $select;
$selects[count($selects)-1]['where'][] = $owner_or;
if ($params['enum_recuring'])
{
$selects[count($selects)-1]['where'][] = "recur_type IS NULL AND $this->user_table.cal_recur_date=0";
$selects[] = $select;
$selects[count($selects)-1]['where'][] = $user_or[$key];
$selects[count($selects)-1]['where'][] = 'recur_type IS NULL AND cal_recur_date=0';
$selects[] = $select;
$selects[count($selects)-1]['where'][] = $user_or[$key];
$selects[count($selects)-1]['where'][] = 'cal_recur_date=cal_start';
$selects[count($selects)-1]['where'][] = $owner_or;
$selects[count($selects)-1]['where'][] = "$this->user_table.cal_recur_date=cal_start";
}
}
}
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';
$selects[] = $select;
if ($params['enum_recuring'])
{
$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)
$countSelects = count($selects);
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[0]['cols'] = $selects[1]['cols'] = "DISTINCT $this->repeats_table.*,$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";
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']);
$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']);
@ -593,7 +612,7 @@ class calendar_so
}
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);
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)
$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();
"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,
$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']))
{
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(
//'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='',
),__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
{
$id = $row['cal_id'];
@ -715,6 +735,7 @@ class calendar_so
}
}
//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;
}

View File

@ -460,16 +460,15 @@ class groupdav_propfind_iterator implements Iterator
*
* @param groupdav_handler $handler
* @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).",)");
$this->path = $path;
$this->handler = $handler;
$this->filter = $filter;
$this->files = $files;
$this->common_files = $files;
$this->files = $this->common_files = $files;
reset($this->files);
}
@ -507,6 +506,12 @@ class groupdav_propfind_iterator implements Iterator
if ($this->debug) error_log(__METHOD__."() returning 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
$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)))
@ -514,10 +519,10 @@ class groupdav_propfind_iterator implements Iterator
if ($this->debug) error_log(__METHOD__."() returning FALSE (no more entries)");
return false; // no further entries
}
$this->start += $entries;
$this->start += self::CHUNK_SIZE;
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;
}
@ -529,11 +534,8 @@ class groupdav_propfind_iterator implements Iterator
{
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;
$files = $this->handler->propfind_callback($this->path,$this->filter,array($this->start,self::CHUNK_SIZE));
$this->files = array_merge($this->common_files, $files);
$this->start += self::CHUNK_SIZE;
$this->files = $this->common_files;
reset($this->files);
}