plugins/calendar plugins/libkolab
Thomas Brüderli
bruederli at kolabsys.com
Thu Feb 5 19:37:26 CET 2015
plugins/calendar/drivers/kolab/kolab_calendar.php | 66 ++++++++++++++++------
plugins/libkolab/lib/kolab_format_xcal.php | 19 +++++-
2 files changed, 65 insertions(+), 20 deletions(-)
New commits:
commit 754a4d51bfa6f08ee7aadff2c3b270e9ca185e28
Author: Thomas Bruederli <bruederli at kolabsys.com>
Date: Thu Feb 5 19:37:03 2015 +0100
Improve search in calendar: consider recurrence exceptions for indexing and matching (#4279); ignore order of search terms (boolean and matching)
diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php
index 9e3ecdf..9d573ee 100644
--- a/plugins/calendar/drivers/kolab/kolab_calendar.php
+++ b/plugins/calendar/drivers/kolab/kolab_calendar.php
@@ -271,27 +271,19 @@ class kolab_calendar extends kolab_storage_folder_api
// remember seen categories
if ($event['categories'])
$this->categories[$event['categories']]++;
-
+
// filter events by search query
if (!empty($search)) {
- $hit = false;
- foreach ($this->search_fields as $col) {
- $sval = is_array($event[$col]) ? self::_complex2string($event[$col]) : $event[$col];
- if (empty($sval))
- continue;
-
- // do a simple substring matching (to be improved)
- $val = mb_strtolower($sval);
- if (strpos($val, $search) !== false) {
- $hit = true;
- break;
- }
+ $hits = 0;
+ $words = rcube_utils::tokenize_string($search, 1);
+ foreach ($words as $word) {
+ $hits += $this->_fulltext_match($event, $word);
}
-
- if (!$hit) // skip this event if not match with search term
+
+ if ($hits < count($words)) // skip this event if not match with search term
continue;
}
-
+
// list events in requested time window
if ($event['start'] <= $end && $event['end'] >= $start) {
unset($event['_attendees']);
@@ -324,6 +316,18 @@ class kolab_calendar extends kolab_storage_folder_api
// resolve recurring events
if ($record['recurrence'] && $virtual == 1) {
$events = array_merge($events, $this->get_recurring_events($record, $start, $end));
+
+ // when searching, only recurrence exceptions may match the query so post-filter the results again
+ if (!empty($search) && $record['recurrence']['EXCEPTIONS']) {
+ $me = $this;
+ $events = array_filter($events, function($event) use ($words, $me) {
+ $hits = 0;
+ foreach ($words as $word) {
+ $hits += $me->_fulltext_match($event, $word, false);
+ }
+ return $hits >= count($words);
+ });
+ }
}
}
@@ -756,6 +760,36 @@ class kolab_calendar extends kolab_storage_folder_api
}
/**
+ * Match the given word in the event contents
+ */
+ private function _fulltext_match($event, $word, $recursive = true)
+ {
+ $hits = 0;
+ foreach ($this->search_fields as $col) {
+ $sval = is_array($event[$col]) ? self::_complex2string($event[$col]) : $event[$col];
+ if (empty($sval))
+ continue;
+
+ // do a simple substring matching (to be improved)
+ $val = mb_strtolower($sval);
+ if (strpos($val, $word) !== false) {
+ $hits++;
+ break;
+ }
+ }
+
+ // search in recurrence exceptions
+ if (!$hits && $recursive && !empty($event['recurrence']['EXCEPTIONS'])) {
+ foreach ($event['recurrence']['EXCEPTIONS'] as $exception) {
+ $hits = $this->_fulltext_match($exception, $word, false);
+ if ($hits) break;
+ }
+ }
+
+ return $hits;
+ }
+
+ /**
* Convert a complex event attribute to a string value
*/
private static function _complex2string($prop)
diff --git a/plugins/libkolab/lib/kolab_format_xcal.php b/plugins/libkolab/lib/kolab_format_xcal.php
index ad54505..33ada93 100644
--- a/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/plugins/libkolab/lib/kolab_format_xcal.php
@@ -581,27 +581,38 @@ abstract class kolab_format_xcal extends kolab_format
*
* @return array List of words to save in cache
*/
- public function get_words()
+ public function get_words($obj = null)
{
$data = '';
+ $object = $obj ?: $this->data;
+
foreach (self::$fulltext_cols as $colname) {
list($col, $field) = explode(':', $colname);
if ($field) {
$a = array();
- foreach ((array)$this->data[$col] as $attr)
+ foreach ((array)$object[$col] as $attr)
$a[] = $attr[$field];
$val = join(' ', $a);
}
else {
- $val = is_array($this->data[$col]) ? join(' ', $this->data[$col]) : $this->data[$col];
+ $val = is_array($object[$col]) ? join(' ', $object[$col]) : $object[$col];
}
if (strlen($val))
$data .= $val . ' ';
}
- return array_unique(rcube_utils::normalize_string($data, true));
+ $words = rcube_utils::normalize_string($data, true);
+
+ // collect words from recurrence exceptions
+ if (is_array($object['recurrence']) && $object['recurrence']['EXCEPTIONS']) {
+ foreach((array)$object['recurrence']['EXCEPTIONS'] as $exception) {
+ $words = array_merge($words, $this->get_words($exception));
+ }
+ }
+
+ return array_unique($words);
}
/**
More information about the commits
mailing list