Overview

Packages

  • Kronolith
  • None

Classes

  • Kronolith
  • Kronolith_Ajax_Application
  • Kronolith_Ajax_Imple_ContactAutoCompleter
  • Kronolith_Ajax_Imple_Embed
  • Kronolith_Ajax_Imple_TagActions
  • Kronolith_Ajax_Imple_TagAutoCompleter
  • Kronolith_Api
  • Kronolith_Calendar
  • Kronolith_Calendar_External
  • Kronolith_Calendar_External_Tasks
  • Kronolith_Calendar_Holiday
  • Kronolith_Calendar_Internal
  • Kronolith_Calendar_Remote
  • Kronolith_Calendar_Resource
  • Kronolith_Calendars_Base
  • Kronolith_Calendars_Default
  • Kronolith_Calendars_Kolab
  • Kronolith_Day
  • Kronolith_Driver
  • Kronolith_Driver_Holidays
  • Kronolith_Driver_Horde
  • Kronolith_Driver_Ical
  • Kronolith_Driver_Kolab
  • Kronolith_Driver_Mock
  • Kronolith_Driver_Resource
  • Kronolith_Driver_Sql
  • Kronolith_Event
  • Kronolith_Event_Holidays
  • Kronolith_Event_Horde
  • Kronolith_Event_Ical
  • Kronolith_Event_Kolab
  • Kronolith_Event_Resource
  • Kronolith_Event_Sql
  • Kronolith_Exception
  • Kronolith_Factory_Calendars
  • Kronolith_Factory_Geo
  • Kronolith_Form_CreateCalendar
  • Kronolith_Form_CreateResource
  • Kronolith_Form_CreateResourceGroup
  • Kronolith_Form_DeleteCalendar
  • Kronolith_Form_DeleteResource
  • Kronolith_Form_DeleteResourceGroup
  • Kronolith_Form_EditCalendar
  • Kronolith_Form_EditRemoteCalendar
  • Kronolith_Form_EditResource
  • Kronolith_Form_EditResourceGroup
  • Kronolith_Form_SubscribeRemoteCalendar
  • Kronolith_Form_UnsubscribeRemoteCalendar
  • Kronolith_FreeBusy
  • Kronolith_FreeBusy_View
  • Kronolith_FreeBusy_View_Day
  • Kronolith_FreeBusy_View_Month
  • Kronolith_FreeBusy_View_Week
  • Kronolith_FreeBusy_View_Workweek
  • Kronolith_Geo_Base
  • Kronolith_Geo_Mysql
  • Kronolith_Geo_Sql
  • Kronolith_LoginTasks_SystemTask_Upgrade
  • Kronolith_LoginTasks_Task_PurgeEvents
  • Kronolith_Notification_Listener_AjaxStatus
  • Kronolith_Resource
  • Kronolith_Resource_Base
  • Kronolith_Resource_Group
  • Kronolith_Resource_Single
  • Kronolith_Storage
  • Kronolith_Storage_Kolab
  • Kronolith_Storage_Sql
  • Kronolith_Tagger
  • Kronolith_Test
  • Kronolith_View_Day
  • Kronolith_View_DeleteEvent
  • Kronolith_View_EditEvent
  • Kronolith_View_Event
  • Kronolith_View_ExportEvent
  • Kronolith_View_Month
  • Kronolith_View_Week
  • Kronolith_View_WorkWeek
  • Kronolith_View_Year
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * Kronolith interface to the Horde_Content tagger
  4:  *
  5:  * Copyright 2009-2012 Horde LLC (http://www.horde.org/)
  6:  *
  7:  * @author Michael J. Rubinsky <mrubinsk@horde.org>
  8:  *
  9:  * @package Kronolith
 10:  */
 11: class Kronolith_Tagger
 12: {
 13:     /**
 14:      * Local cache of the type name => ids from Content, so we don't have to
 15:      * query for them each time.
 16:      *
 17:      * @var array
 18:      */
 19:     protected $_type_ids = array();
 20: 
 21:     /**
 22:      * Constructor.
 23:      *
 24:      * @return Kronolith_Tagger
 25:      */
 26:     public function __construct()
 27:     {
 28:         // Remember the types to avoid having Content query them again.
 29:         $key = 'kronolith.tagger.type_ids';
 30:         $ids = $GLOBALS['injector']->getInstance('Horde_Cache')->get($key, 360);
 31:         if ($ids) {
 32:             $this->_type_ids = unserialize($ids);
 33:         } else {
 34:             $type_mgr = $GLOBALS['injector']->getInstance('Content_Types_Manager');
 35:             $types = $type_mgr->ensureTypes(array('calendar', 'event'));
 36:             $this->_type_ids = array('calendar' => (int)$types[0],
 37:                                      'event' => (int)$types[1]);
 38:             $GLOBALS['injector']->getInstance('Horde_Cache')->set($key, serialize($this->_type_ids));
 39:         }
 40:     }
 41: 
 42:     /**
 43:      * Tags a kronolith object with any number of tags.
 44:      *
 45:      * @param string $localId       The identifier of the kronolith object.
 46:      * @param mixed $tags           Either a single tag string or an array of
 47:      *                              tags.
 48:      * @param string $owner         The tag owner (should normally be the owner
 49:      *                              of the resource).
 50:      * @param string $content_type  The type of object we are tagging
 51:      *                              (event/calendar).
 52:      *
 53:      * @return void
 54:      */
 55:     public function tag($localId, $tags, $owner, $content_type = 'event')
 56:     {
 57:         // If we don't have an array - split the string.
 58:         if (!is_array($tags)) {
 59:             $tags = $GLOBALS['injector']->getInstance('Content_Tagger')->splitTags($tags);
 60:         }
 61: 
 62:         $GLOBALS['injector']->getInstance('Content_Tagger')->tag(
 63:                 $owner,
 64:                 array('object' => $localId,
 65:                       'type' => $this->_type_ids[$content_type]),
 66:                 $tags);
 67:     }
 68: 
 69:     /**
 70:      * Retrieves the tags on given object(s).
 71:      *
 72:      * @param mixed  $localId  Either the identifier of the kronolith object or
 73:      *                         an array of identifiers.
 74:      * @param string $type     The type of object $localId represents.
 75:      *
 76:      * @return array A tag_id => tag_name hash, possibly wrapped in a localid hash.
 77:      */
 78:     public function getTags($localId, $type = 'event')
 79:     {
 80:         if (is_array($localId)) {
 81:             return $GLOBALS['injector']->getInstance('Content_Tagger')->getTagsByObjects($localId, $type);
 82:         }
 83: 
 84:         return $GLOBALS['injector']->getInstance('Content_Tagger')->getTags(array('objectId' => array('object' => $localId, 'type' => $this->_type_ids[$type])));
 85:     }
 86: 
 87:     /**
 88:      * Removes a tag from a kronolith object.
 89:      *
 90:      * Removes *all* tags - regardless of the user that added the tag.
 91:      *
 92:      * @param string $localId       The kronolith object identifier.
 93:      * @param mixed $tags           Either a tag_id, tag_name or an array of
 94:      *                              ids or names to remove.
 95:      * @param string $content_type  The type of object that $localId represents.
 96:      */
 97:     public function untag($localId, $tags, $content_type = 'event')
 98:     {
 99:         $GLOBALS['injector']->getInstance('Content_Tagger')->removeTagFromObject(
100:             array('object' => $localId, 'type' => $this->_type_ids[$content_type]), $tags);
101:     }
102: 
103:     /**
104:      * Tags the given resource with *only* the tags provided, removing any
105:      * tags that are already present but not in the list.
106:      *
107:      * @param string $localId  The identifier for the kronolith object.
108:      * @param mixed $tags      Either a tag_id, tag_name, or array of tag_ids.
109:      * @param string $owner    The tag owner - should normally be the resource
110:      *                         owner.
111:      * @param $content_type    The type of object that $localId represents.
112:      */
113:     public function replaceTags($localId, $tags, $owner, $content_type = 'event')
114:     {
115:         // First get a list of existing tags.
116:         $existing_tags = $this->getTags($localId, $content_type);
117: 
118:         // If we don't have an array - split the string.
119:         if (!is_array($tags)) {
120:             $tags = $GLOBALS['injector']->getInstance('Content_Tagger')->splitTags($tags);
121:         }
122:         $remove = array();
123:         foreach ($existing_tags as $tag_id => $existing_tag) {
124:             $found = false;
125:             foreach ($tags as $tag_text) {
126:                 if ($existing_tag == $tag_text) {
127:                     $found = true;
128:                     break;
129:                 }
130:             }
131:             // Remove any tags that were not found in the passed in list.
132:             if (!$found) {
133:                 $remove[] = $tag_id;
134:             }
135:         }
136: 
137:         $this->untag($localId, $remove, $content_type);
138:         $add = array();
139:         foreach ($tags as $tag_text) {
140:             $found = false;
141:             foreach ($existing_tags as $existing_tag) {
142:                 if ($tag_text == $existing_tag) {
143:                     $found = true;
144:                     break;
145:                 }
146:             }
147:             if (!$found) {
148:                 $add[] = $tag_text;
149:             }
150:         }
151: 
152:         $this->tag($localId, $add, $owner, $content_type);
153:     }
154: 
155:     /**
156:      * Searches for resources that are tagged with all of the requested tags.
157:      *
158:      * @param array $tags    Either a tag_id, tag_name or an array.
159:      * @param array $filter  Array of filter parameters.
160:      *                       - type (string) - only return either events or
161:      *                         calendars, not both.
162:      *                       - user (array) - only include objects owned by
163:      *                         these users.
164:      *                       - calendar (array) - restrict to events contained
165:      *                         in these calendars.
166:      *
167:      * @return  A hash of 'calendars' and 'events' that each contain an array
168:      *          of calendar_ids and event_uids respectively.
169:      */
170:     public function search($tags, $filter = array())
171:     {
172:         $args = array();
173: 
174:         /* These filters are mutually exclusive */
175:         if (array_key_exists('user', $filter)) {
176:             /* semi-hack to see if we are querying for a system-owned share -
177:              * will need to get the list of all system owned shares and query
178:              * using a calendar filter instead of a user filter. */
179:             if (empty($filter['user'])) {
180:                 // @TODO: No way to get only the system shares the current
181:                 // user can see?
182:                 $calendars = $GLOBALS['kronolith_shares']->listSystemShares();
183:                 $args['calendarId'] = array();
184:                 foreach ($calendars as $name => $share) {
185:                     if ($share->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::READ)) {
186:                         $args['calendarId'][] = $name;
187:                     }
188:                 }
189:             } else {
190:                 // Items owned by specific user(s)
191:                 $args['userId'] = $filter['user'];
192:             }
193:         } elseif (!empty($filter['calendar'])) {
194:             // Only events located in specific calendar(s)
195:             if (!is_array($filter['calendar'])) {
196:                 $filter['calendar'] = array($filter['calendar']);
197:             }
198:             $args['calendarId'] = $filter['calendar'];
199:         }
200: 
201:         /* Add the tags to the search */
202:         $args['tagId'] = $GLOBALS['injector']->getInstance('Content_Tagger')->getTagIds($tags);
203: 
204:         /* Restrict to events or calendars? */
205:         $cal_results = $event_results = array();
206:         if (empty($filter['type']) || $filter['type'] == 'calendar') {
207:             $args['typeId'] = $this->_type_ids['calendar'];
208:             $cal_results = $GLOBALS['injector']->getInstance('Content_Tagger')->getObjects($args);
209:         }
210: 
211:         if (empty($filter['type']) || $filter['type'] == 'event') {
212:             $args['typeId'] = $this->_type_ids['event'];
213:             $event_results = $GLOBALS['injector']->getInstance('Content_Tagger')->getObjects($args);
214:         }
215: 
216:         $results = array('calendars' => array_values($cal_results),
217:                          'events' => (!empty($args['calendarId']) && count($event_results))
218:                                      ? Kronolith::getDriver()->filterEventsByCalendar(array_values($event_results), $args['calendarId'])
219:                                      : array_values($event_results));
220: 
221:         return $results;
222:     }
223: 
224:     /**
225:      * Returns tags belonging to the current user beginning with $token.
226:      *
227:      * Used for autocomplete code.
228:      *
229:      * @param string $token  The token to match the start of the tag with.
230:      *
231:      * @return A tag_id => tag_name hash
232:      */
233:     public function listTags($token)
234:     {
235:         return $GLOBALS['injector']->getInstance('Content_Tagger')->getTags(
236:                 array('q' => $token, 'userId' => $GLOBALS['registry']->getAuth()));
237:     }
238: 
239:     /**
240:      * Returns the data needed to build a tag cloud based on the passed in
241:      * user's tag data set.
242:      *
243:      * @param string $user    The user whose tags should be included.
244:      * @param integer $limit  The maximum number of tags to include.
245:      *
246:      * @return An array of hashes, each containing tag_id, tag_name, and count.
247:      */
248:     public function getCloud($user, $limit = 5)
249:     {
250:         return $GLOBALS['injector']->getInstance('Content_Tagger')->getTagCloud(
251:                 array('userId' => $user, 'limit' => $limit));
252:     }
253: 
254:     /**
255:      * Returns cloud-like information, but only for a specified set of tags.
256:      *
257:      * @param array $tags     An array of either tag names or ids.
258:      * @param integer $limit  Limit results to this many.
259:      * @param string $type    The type of resource (event, calendar, null).
260:      * @param string $user    Restrict results to those tagged by $user.
261:      *
262:      * @return array  An array of hashes, tag_id, tag_name, and count.
263:      * @throws Ansel_Exception
264:      */
265:     public function getTagInfo($tags = null, $limit = 500, $type = null, $user = null)
266:     {
267:         $filter = array(
268:             'typeId' => empty($type) ? array_values($this->_type_ids) : $this->_type_ids[$type],
269:             'tagIds' => $tags,
270:             'limit' => $limit,
271:             'userId' => $user
272:         );
273: 
274:         try {
275:             return $GLOBALS['injector']
276:                 ->getInstance('Content_Tagger')
277:                 ->getTagCloud($filter);
278:         } catch (Content_Exception $e) {
279:             throw new Ansel_Exception($e);
280:         }
281:     }
282: 
283: }
284: 
API documentation generated by ApiGen