1: <?php
2: /**
3: * Kronolith_Driver defines an API for implementing storage backends for
4: * Kronolith.
5: *
6: * Copyright 1999-2012 Horde LLC (http://www.horde.org/)
7: *
8: * See the enclosed file COPYING for license information (GPL). If you
9: * did not receive this file, see http://www.horde.org/licenses/gpl.
10: *
11: * @author Chuck Hagenbuch <chuck@horde.org>
12: * @author Jan Schneider <jan@horde.org>
13: * @package Kronolith
14: */
15: class Kronolith_Driver
16: {
17: /**
18: * The current calendar.
19: *
20: * @var string
21: */
22: public $calendar;
23:
24: /**
25: * The HTML background color to be used for this event.
26: *
27: * @var string
28: */
29: public $backgroundColor = '#ddd';
30:
31: /**
32: * The HTML foreground color to be used for this event.
33: *
34: * @var string
35: */
36: public $foregroundColor = '#000';
37:
38: /**
39: * A hash containing any parameters for the current driver.
40: *
41: * @var array
42: */
43: protected $_params = array();
44:
45: /**
46: * An error message to throw when something is wrong.
47: *
48: * @var string
49: */
50: private $_errormsg;
51:
52: /**
53: * Constructor.
54: *
55: * Just stores the $params in our newly-created object. All other work is
56: * done by {@link initialize()}.
57: *
58: * @param array $params Any parameters needed for this driver.
59: * @param string $errormsg A custom error message to use.
60: */
61: public function __construct(array $params = array(), $errormsg = null)
62: {
63: $this->_params = $params;
64: if ($errormsg === null) {
65: $this->_errormsg = _("The Calendar backend is not currently available.");
66: } else {
67: $this->_errormsg = $errormsg;
68: }
69: }
70:
71: /**
72: * Returns a configuration for this driver.
73: *
74: * @param string $param A parameter name.
75: *
76: * @return mixed The parameter value or null if not set.
77: */
78: public function getParam($param)
79: {
80: return isset($this->_params[$param]) ? $this->_params[$param] : null;
81: }
82:
83: /**
84: * Sets a configuration for this driver.
85: *
86: * @param string $param A parameter name.
87: * @param mixed $value The parameter value.
88: */
89: public function setParam($param, $value)
90: {
91: $this->_params[$param] = $value;
92: }
93:
94: /**
95: * Sets all configuration parameters for this driver.
96: *
97: * @param string $params A parameters hash.
98: */
99: public function setParams($params)
100: {
101: $this->_params = $params;
102: }
103:
104: /**
105: * Selects a calendar as the currently opened calendar.
106: *
107: * @param string $calendar A calendar identifier.
108: */
109: public function open($calendar)
110: {
111: $this->calendar = $calendar;
112: }
113:
114: /**
115: * Returns the background color of the current calendar.
116: *
117: * @return string The calendar color.
118: */
119: public function backgroundColor()
120: {
121: return '#dddddd';
122: }
123:
124: /**
125: * Returns the colors of the current calendar.
126: *
127: * @return array The calendar background and foreground color.
128: */
129: public function colors()
130: {
131: $color = $this->backgroundColor();
132: return array($color, Kronolith::foregroundColor($color));
133: }
134:
135: /**
136: * Searches a calendar.
137: *
138: * @param object $query An object with the criteria to search for.
139: * @param boolean $json Store the results of the events' toJson() method?
140: *
141: * @return mixed An array of Kronolith_Events.
142: * @throws Kronolith_Exception
143: */
144: public function search($query, $json = false)
145: {
146: /* Our default implementation first gets <em>all</em> events in a
147: * specific period, and then filters based on the actual values that
148: * are filled in. Drivers can optimize this behavior if they have the
149: * ability. */
150: $results = array();
151:
152: $events = $this->listEvents(
153: (!empty($query->start) ? $query->start : null),
154: (!empty($query->end) ? $query->end : null));
155: foreach ($events as $day => $day_events) {
156: foreach ($day_events as $event) {
157: if ((((!isset($query->start) ||
158: $event->end->compareDateTime($query->start) > 0) &&
159: (!isset($query->end) ||
160: $event->end->compareDateTime($query->end) < 0)) ||
161: ($event->recurs() &&
162: $event->end->compareDateTime($query->start) >= 0 &&
163: $event->start->compareDateTime($query->end) <= 0)) &&
164: (empty($query->title) ||
165: stristr($event->getTitle(), $query->title)) &&
166: (empty($query->location) ||
167: stristr($event->location, $query->location)) &&
168: (empty($query->description) ||
169: stristr($event->description, $query->description)) &&
170: (empty($query->creator) ||
171: stristr($event->creator, $query->creator)) &&
172: (!isset($query->status) ||
173: $event->status == $query->status)) {
174: Kronolith::addEvents($results, $event, $event->start, $event->end, false, $json, false);
175: }
176: }
177: }
178:
179: return $results;
180: }
181:
182: /**
183: * Finds the next recurrence of $eventId that's after $afterDate.
184: *
185: * @param string $eventId The ID of the event to fetch.
186: * @param Horde_Date $afterDate Return events after this date.
187: *
188: * @return Horde_Date|boolean The date of the next recurrence or false if
189: * the event does not recur after $afterDate.
190: * @throws Kronolith_Exception
191: * @throws Horde_Exception_NotFound
192: */
193: public function nextRecurrence($eventId, $afterDate)
194: {
195: $event = $this->getEvent($eventId);
196: return $event->recurs() ? $event->recurrence->nextRecurrence($afterDate) : false;
197: }
198:
199: /**
200: * Returns the number of events in the current calendar.
201: *
202: * @return integer The number of events.
203: * @throws Kronolith_Exception
204: */
205: public function countEvents()
206: {
207: $count = 0;
208: foreach ($this->listEvents() as $dayevents) {
209: $count += count($dayevents);
210: }
211: return $count;
212: }
213:
214: /**
215: * Stub to initiate a driver.
216: *
217: * @throws Kronolith_Exception
218: */
219: public function initialize()
220: {
221: return true;
222: }
223:
224: /**
225: * Stub to be overridden in the child class.
226: *
227: * @throws Kronolith_Exception
228: * @throws Horde_Exception_NotFound
229: */
230: public function getEvent()
231: {
232: throw new Kronolith_Exception($this->_errormsg);
233: }
234:
235: /**
236: * Stub to be overridden in the child class.
237: *
238: * @throws Kronolith_Exception
239: * @throws Horde_Exception_NotFound
240: */
241: public function getByUID($uid, $calendars = null, $getAll = false)
242: {
243: throw new Kronolith_Exception($this->_errormsg);
244: }
245:
246: /**
247: * Stub to be overridden in the child class.
248: *
249: * @throws Kronolith_Exception
250: */
251: public function listAlarms($date, $fullevent = false)
252: {
253: throw new Kronolith_Exception($this->_errormsg);
254: }
255:
256: /**
257: * Stub to be overridden in the child class.
258: *
259: * @throws Kronolith_Exception
260: */
261: public function listEvents()
262: {
263: throw new Kronolith_Exception($this->_errormsg);
264: }
265:
266: /**
267: * Saves an event in the backend.
268: *
269: * If it is a new event, it is added, otherwise the event is updated.
270: *
271: * @param Kronolith_Event $event The event to save.
272: *
273: * @return string The event id.
274: * @throws Horde_Mime_Exception
275: * @throws Kronolith_Exception
276: */
277: public function saveEvent(Kronolith_Event $event)
278: {
279: if ($event->stored || $event->exists()) {
280: return $this->_updateEvent($event);
281: }
282: return $this->_addEvent($event);
283: }
284:
285: /**
286: * Stub to be overridden in the child class.
287: *
288: * @throws Kronolith_Exception
289: */
290: protected function _addEvent(Kronolith_Event $event)
291: {
292: throw new Kronolith_Exception($this->_errormsg);
293: }
294:
295: /**
296: * Stub to be overridden in the child class.
297: *
298: * @throws Kronolith_Exception
299: */
300: protected function _updateEvent(Kronolith_Event $event)
301: {
302: throw new Kronolith_Exception($this->_errormsg);
303: }
304:
305: /**
306: * Stub for child class to override if it can implement.
307: *
308: * @throws Kronolith_Exception
309: */
310: public function exists($uid, $calendar_id = null)
311: {
312: throw new Kronolith_Exception('Not supported');
313: }
314:
315: /**
316: * Moves an event to a new calendar.
317: *
318: * @param string $eventId The event to move.
319: * @param string $newCalendar The new calendar.
320: *
321: * @throws Kronolith_Exception
322: * @throws Horde_Exception_NotFound
323: */
324: public function move($eventId, $newCalendar)
325: {
326: $event = $this->_move($eventId, $newCalendar);
327:
328: /* Log the moving of this item in the history log. */
329: $uid = $event->uid;
330: if ($uid) {
331: $history = $GLOBALS['injector']->getInstance('Horde_History');
332: try {
333: $history->log('kronolith:' . $event->calendar . ':' . $uid, array('action' => 'delete'), true);
334: $history->log('kronolith:' . $newCalendar . ':' . $uid, array('action' => 'add'), true);
335: } catch (Exception $e) {
336: Horde::logMessage($e, 'ERR');
337: }
338: }
339: }
340:
341: /**
342: * Stub to be overridden in the child class.
343: *
344: * @throws Kronolith_Exception
345: */
346: protected function _move($eventId, $newCalendar)
347: {
348: throw new Kronolith_Exception('Not supported');
349: }
350:
351: /**
352: * Stub to be overridden in the child class.
353: *
354: * @throws Kronolith_Exception
355: */
356: public function delete($calendar)
357: {
358: throw new Kronolith_Exception('Not supported');
359: }
360:
361: /**
362: * Stub to be overridden in the child class.
363: */
364: public function deleteEvent($eventId)
365: {
366: }
367:
368: /**
369: * Stub to be overridden in the child class if it can implement.
370: *
371: * @throws Kronolith_Exception
372: */
373: public function filterEventsByCalendar($uids, $calendar)
374: {
375: throw new Kronolith_Exception('Not supported');
376: }
377:
378: /**
379: * Stub for child class to override if it can implement.
380: *
381: * @todo Remove in Kronolith 4.0
382: * @deprecated Now lives in Kronolith::
383: * @throws Kronolith_Exception
384: */
385: public function removeUserData($user)
386: {
387: throw new Kronolith_Exception('Deprecated.');
388: }
389: }
390: