Improvments in listing events - do not query tag storage when listing events.
authorMichael J. Rubinsky <mrubinsk@horde.org>
Fri, 28 May 2010 18:58:54 +0000 (14:58 -0400)
committerMichael J. Rubinsky <mrubinsk@horde.org>
Fri, 28 May 2010 18:58:54 +0000 (14:58 -0400)
No need to query tag storage 99% of the time we call listEvents. Do not retrieve tags
unless explicitly requested, and when we do, do it in a single batch query for all events
returned in listEvents.  Also, lazy load the tags on events when accessing the tags property.

Still need to do something similar with the geoLocation stuff.

framework/ActiveSync/lib/Horde/ActiveSync/Driver/Horde/Connector/Registry.php
kronolith/lib/Api.php
kronolith/lib/Driver/Kolab.php
kronolith/lib/Driver/Sql.php
kronolith/lib/Event.php
kronolith/lib/Event/Kolab.php
kronolith/lib/Kronolith.php
kronolith/lib/Resource/Single.php
kronolith/lib/Tagger.php

index a190e56..5ad961a 100644 (file)
@@ -58,7 +58,8 @@ class Horde_ActiveSync_Driver_Horde_Connector_Registry
                     false,         // Alarms only
                     false,         // Show remote
                     true,          // Hide exception events
-                    false);        // Don't return multi-day events on *each* day
+                    false,         // Don't return multi-day events on *each* day
+                    true);         // Return Tags
         } catch (Exception $e) {
             return array();
         }
@@ -108,7 +109,7 @@ class Horde_ActiveSync_Driver_Horde_Connector_Registry
      *
      * @param string $uid          The calendar id
      *
-     * @return The iCalendar representation of the calendar
+     * @return Horde_ActiveSync_Message_Appointment
      */
     public function calendar_export($uid)
     {
index 77b4018..12b3d01 100644 (file)
@@ -790,7 +790,7 @@ class Kronolith_Api extends Horde_Registry_Api
         }
 
         $kronolith_driver = Kronolith::getDriver(null, $calendar);
-        $events = $kronolith_driver->listEvents();
+        $events = $kronolith_driver->listEvents(null, null, null, true, false, true, false, true, true);
 
         $version = '2.0';
         switch ($contentType) {
@@ -1096,7 +1096,7 @@ class Kronolith_Api extends Horde_Registry_Api
     public function listEvents($startstamp = null, $endstamp = null,
         $calendars = null, $showRecurrence = true,
         $alarmsOnly = false, $showRemote = true, $hideExceptions = false,
-        $coverDates = true)
+        $coverDates = true, $fetchTags = false)
     {
         if (!isset($calendars)) {
             $calendars = array($GLOBALS['prefs']->getValue('default_share'));
@@ -1118,7 +1118,8 @@ class Kronolith_Api extends Horde_Registry_Api
             $alarmsOnly,
             $showRemote,
             $hideExceptions,
-            $coverDates);
+            $coverDates,
+            $fetchTags);
     }
 
     /**
index 2855c31..a24c7c5 100644 (file)
@@ -215,7 +215,8 @@ class Kronolith_Driver_Kolab extends Kronolith_Driver
      */
     public function listEvents($startDate = null, $endDate = null,
                                $showRecurrence = false, $hasAlarm = false,
-                               $json = false, $coverDates = true)
+                               $json = false, $coverDates = true,
+                               $fetchTags = false)
     {
         $result = $this->synchronize();
 
@@ -363,11 +364,10 @@ class Kronolith_Driver_Kolab extends Kronolith_Driver
         $result = $this->_store->save($attributes, $stored_uid);
 
         /* Deal with tags */
-        $tagger = Kronolith::getTagger();
         if (!empty($edit)) {
-            $tagger->replaceTags($event->uid, $event->tags, $event->creator, 'event');
+            Kronolith::getTagger()->replaceTags($event->uid, $event->tags, $event->creator, 'event');
         } else {
-            $tagger->tag($event->uid, $event->tags, $event->creator, 'event');
+            Kronolith::getTagger()->tag($event->uid, $event->tags, $event->creator, 'event');
         }
 
         $cal = $GLOBALS['kronolith_shares']->getShare($event->calendar);
index 0490f10..2b547ec 100644 (file)
@@ -244,13 +244,15 @@ class Kronolith_Driver_Sql extends Kronolith_Driver
      *                                   toJson() method?
      * @param boolean $coverDates        Whether to add the events to all days
      *                                   that they cover.
+     * @param boolean $fetchTags         Whether to fetch tags for all events
      *
      * @return array  Events in the given time range.
      * @throws Kronolith_Exception
      */
     public function listEvents($startDate = null, $endDate = null,
                                $showRecurrence = false, $hasAlarm = false,
-                               $json = false, $coverDates = true, $hideExceptions = false)
+                               $json = false, $coverDates = true, $hideExceptions = false,
+                               $fetchTags = false)
     {
         if (!is_null($startDate)) {
             $startDate = clone $startDate;
@@ -273,9 +275,16 @@ class Kronolith_Driver_Sql extends Kronolith_Driver
 
         $events = $this->_listEventsConditional($startDate, $endDate, $conditions, $values);
         $results = array();
+        if ($fetchTags) {
+            $tags = Kronolith::getTagger()->getTags(array_keys($events));
+        }
         foreach ($events as $id) {
-            Kronolith::addEvents($results, $this->getEvent($id), $startDate,
-                                 $endDate, $showRecurrence, $json, $coverDates);
+            $event = $this->getEvent($id);
+            if (isset($tags) && !empty($tags[$event->uid])) {
+                $event->setTags($tags[$event->uid]);
+            }
+            Kronolith::addEvents($results, $event, $startDate, $endDate,
+                                 $showRecurrence, $json, $coverDates);
         }
 
         return $results;
@@ -584,8 +593,7 @@ class Kronolith_Driver_Sql extends Kronolith_Driver
              }
 
             /* Update tags */
-            $tagger = Kronolith::getTagger();
-            $tagger->replaceTags($event->uid, $event->tags, $event->creator, 'event');
+            Kronolith::getTagger()->replaceTags($event->uid, $event->tags, $event->creator, 'event');
 
             /* Add tags again, but as the share owner (replaceTags removes ALL tags). */
             try {
@@ -593,7 +601,7 @@ class Kronolith_Driver_Sql extends Kronolith_Driver
             } catch (Horde_Share_Exception $e) {
                 throw new Kronolith_Exception($e);
             }
-            $tagger->tag($event->uid, $event->tags, $cal->get('owner'), 'event');
+            Kronolith::getTagger()->tag($event->uid, $event->tags, $cal->get('owner'), 'event');
 
             /* Update Geolocation */
             if ($gDriver = Kronolith::getGeoDriver()) {
index c5c641f..a979ec1 100644 (file)
@@ -112,7 +112,7 @@ abstract class Kronolith_Event
      *
      * @var array|string
      */
-    public $tags = array();
+    protected $_tags = null;
 
     /**
      * Geolocation
@@ -300,10 +300,6 @@ abstract class Kronolith_Event
         if (!is_null($eventObject)) {
             $this->fromDriver($eventObject);
 
-            /* Get tags */
-            $tagger = Kronolith::getTagger();
-            $this->tags = $tagger->getTags($this->uid, 'event');
-
             /* Get geolocation data */
             if ($gDriver = Kronolith::getGeoDriver()) {
                 try {
@@ -368,6 +364,8 @@ abstract class Kronolith_Event
         case 'span':
         case 'rowspan':
             return $this->{'_' . $name};
+        case 'tags':
+            return $this->getTags();
         }
         $trace = debug_backtrace();
         trigger_error('Undefined property via __set(): ' . $name
@@ -781,7 +779,7 @@ abstract class Kronolith_Event
         // Tags
         $categories = $vEvent->getAttributeValues('CATEGORIES');
         if (!($categories instanceof PEAR_Error)) {
-            $this->tags = $categories;
+            $this->_tags = $categories;
         }
 
         // Description
@@ -2244,7 +2242,7 @@ abstract class Kronolith_Event
         }
 
         // Tags.
-        $this->tags = Horde_Util::getFormData('tags', $this->tags);
+        $this->_tags = Horde_Util::getFormData('tags', $this->tags);
 
         // Geolocation
         $this->geoLocation = array('lat' => Horde_Util::getFormData('lat'),
@@ -2706,6 +2704,30 @@ abstract class Kronolith_Event
         return 'kronolithEvent';
     }
 
+    /**
+     * Setter for tags
+     *
+     * @param array $tags  An array of tag_names
+     */
+    public function setTags($tags)
+    {
+        $this->_tags = $tags;
+    }
+
+    /**
+     * Getter for tags
+     *
+     * @return mixed  An array of tag_names, or false if tags were never set.
+     */
+    public function getTags()
+    {
+        if (!isset($this->_tags)) {
+            $this->_tags = Kronolith::getTagger()->getTags($this->uid, 'event');
+        }
+
+        return $this->_tags;
+    }
+
     private function _formIDEncode($id)
     {
         return str_replace(array('[', ']'),
index e05f1b5..e60024f 100644 (file)
@@ -39,6 +39,7 @@ class Kronolith_Event_Kolab extends Kronolith_Event
         $this->alarm = $alarm;
 
         parent::__construct($driver, $eventObject);
+        $this->_tags = Kronolith::getTagger()->getTags($this->uid, 'event');
     }
 
     public function fromDriver($event)
index 99bca32..343c412 100644 (file)
@@ -466,6 +466,8 @@ class Kronolith
      *                                 listTimeObjects as well?
      * @param boolean $hideExceptions  Hide events that represent exceptions to
      *                                 a recurring event?
+     * @param boolean $fetchTags       Should we fetch each event's tags from
+     *                                 storage?
      *
      * @return array  The events happening in this time period.
      * @throws Kronolith_Exception
@@ -473,7 +475,8 @@ class Kronolith
     public static function listEvents($startDate, $endDate, $calendars = null,
                                       $showRecurrence = true,
                                       $alarmsOnly = false, $showRemote = true,
-                                      $hideExceptions = false, $coverDates = true)
+                                      $hideExceptions = false, $coverDates = true,
+                                      $fetchTags = false)
     {
         $results = array();
 
@@ -486,7 +489,7 @@ class Kronolith
             $driver->open($calendar);
             $events = $driver->listEvents($startDate, $endDate, $showRecurrence,
                                           $alarmsOnly, false, $coverDates,
-                                          $hideExceptions);
+                                          $hideExceptions, $fetchTags);
             
             self::mergeEvents($results, $events);
         }
index 2ac8f04..cc2991e 100644 (file)
@@ -156,7 +156,7 @@ class Kronolith_Resource_Single extends Kronolith_Resource_Base
         $to->status = $from->status;
         $to->description = $from->description;
         $to->url = $from->url;
-        $to->tags = $from->tags;
+        $to->setTags($from->tags);
         $to->geoLocation = $from->geoLocation;
         $to->first = $from ->first;
         $to->last = $from->last;
index 8091d26..b70c687 100644 (file)
@@ -36,7 +36,7 @@ class Kronolith_Tagger
         $this->_type_ids = array('calendar' => (int)$types[0],
                                  'event' => (int)$types[1]);
 
-        // Cache the tagger statically
+        // Cache the tagger
         $this->_tagger = $GLOBALS['injector']->getInstance('Content_Tagger');
     }
 
@@ -69,22 +69,19 @@ class Kronolith_Tagger
     /**
      * Retrieves the tags on given object(s).
      *
-     * @param string $localId  The identifier of the kronolith object.
+     * @param mixed  $localId  Either the identifier of the kronolith object or
+     *                         an array of identifiers.
      * @param string $type     The type of object $localId represents.
      *
-     * @return a tag_id => tag_name hash.
+     * @return array A tag_id => tag_name hash, possibly wrapped in a localid hash.
      */
     public function getTags($localId, $type = 'event')
     {
-        if (!is_array($localId)) {
-            $localId = array($localId);
-        }
-        $tags = array();
-        foreach ($localId as $id) {
-            $tags = $tags + $this->_tagger->getTags(array('objectId' => array('object' => $id, 'type' => $this->_type_ids[$type])));
+        if (is_array($localId)) {
+            return $this->_tagger->getTagsByObjects($localId, $type);
         }
 
-        return $tags;
+        return $this->_tagger->getTags(array('objectId' => array('object' => $localId, 'type' => $this->_type_ids[$type])));
     }
 
     /**