--- /dev/null
+<?php
+/**
+ * @package Horde_Alarm
+ *
+ * Copyright 2010 The Horde Project (http://www.horde.org/)
+ *
+ * See the enclosed file COPYING for license information (LGPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
+ */
+
+/**
+ * The Horde_Alarm_Object:: class is a Horde_Alarm storage implementation
+ * using an object instance.
+ *
+ * @author Jan Schneider <jan@horde.org>
+ * @package Horde_Alarm
+ */
+class Horde_Alarm_Object extends Horde_Alarm
+{
+ protected $_alarms = array();
+
+ /**
+ * Returns a certain alarm.
+ *
+ * @param string $id The alarm's unique id.
+ * @param string $user The alarm's user.
+ *
+ * @return array An alarm hash.
+ */
+ protected function &_findAlarm($id, $user)
+ {
+ foreach ($this->_alarms as &$alarm) {
+ if ($alarm['id'] == $id && $alarm['user'] === $user) {
+ return $alarm;
+ }
+ }
+ $result = null;
+ return $result;
+ }
+
+ /**
+ * Sorts a number of alarms in chronological order.
+ */
+ protected function _sortAlarms($a, $b)
+ {
+ $cmp = $a['start']->compareDateTime($b['start']);
+ if ($cmp) {
+ return $cmp;
+ }
+ if (empty($a['end'])) {
+ return -1;
+ }
+ if (empty($b['end'])) {
+ return 1;
+ }
+ return $a['end']->compareDateTime($b['end']);
+ }
+
+ /**
+ * Returns a list of alarms from the backend.
+ *
+ * @param Horde_Date $time The time when the alarms should be active.
+ * @param string $user Return alarms for this user, all users if
+ * null, or global alarms if empty.
+ *
+ * @return array A list of alarm hashes.
+ * @throws Horde_Alarm_Exception
+ */
+ protected function _list($user, Horde_Date $time)
+ {
+ $alarms = array();
+ foreach ($this->_alarms as $alarm) {
+ if (empty($alarm['dismissed']) &&
+ ((empty($alarm['snooze']) && $alarm['start']->compareDateTime($time) <= 0) ||
+ $alarm['snooze']->compareDateTime($time) <= 0) &&
+ (empty($alarm['end']) || $alarm['end']->compareDateTime($time) => 0) &&
+ (is_null($user) || empty($alarm['uid']) || $alarm['uid'] = $user)) {
+ $alarms[] = $alarm;
+ }
+ }
+ usort($alarms, array($this, '_sortAlarms'));
+ return $alarms;
+ }
+
+ /**
+ * Returns an alarm hash from the backend.
+ *
+ * @param string $id The alarm's unique id.
+ * @param string $user The alarm's user.
+ *
+ * @return array An alarm hash.
+ * @throws Horde_Alarm_Exception
+ */
+ protected function _get($id, $user)
+ {
+ $alarm = $this->_findAlarm($id, $user);
+ if (!$alarm) {
+ throw new Horde_Alarm_Exception('Alarm not found');
+ }
+ return $alarm;
+ }
+
+ /**
+ * Adds an alarm hash to the backend.
+ *
+ * @param array $alarm An alarm hash.
+ */
+ protected function _add(array $alarm)
+ {
+ $alarm = array_merge(
+ array('user' => '',
+ 'end' => null,
+ 'text' => null,
+ 'snooze' => null,
+ 'internal' => null),
+ $alarm);
+ $this->_alarms[] = $alarm;
+ }
+
+ /**
+ * Updates an alarm hash in the backend.
+ *
+ * @param array $alarm An alarm hash.
+ * @param boolean $keepsnooze Whether to keep the snooze value unchanged.
+ */
+ protected function _update(array $alarm, $keepsnooze = false)
+ {
+ $user = isset($alarm['user']) ? $alarm['user'] : null;
+ $al = &$this->_findAlarm($alarm['id'], $user);
+
+ foreach (array('start', 'end', 'methods', 'params', 'title', 'text') as $property) {
+ $al[$property] = $alarm[$property];
+ }
+ if (!$keepsnooze) {
+ $al['snooze'] = null;
+ }
+ }
+
+ /**
+ * Updates internal alarm properties, i.e. properties not determined by
+ * the application setting the alarm.
+ *
+ * @param string $id The alarm's unique id.
+ * @param string $user The alarm's user
+ * @param array $internal A hash with the internal data.
+ *
+ * @throws Horde_Alarm_Exception
+ */
+ protected function _internal($id, $user, array $internal)
+ {
+ $alarm = &$this->_findAlarm($id, $user);
+ $alarm['internal'] = $internal;
+ }
+
+ /**
+ * Returns whether an alarm with the given id exists already.
+ *
+ * @param string $id The alarm's unique id.
+ * @param string $user The alarm's user
+ *
+ * @return boolean True if the specified alarm exists.
+ * @throws Horde_Alarm_Exception
+ */
+ protected function _exists($id, $user)
+ {
+ return (bool)$this->_findAlarm($id, $user);
+ }
+
+ /**
+ * Delays (snoozes) an alarm for a certain period.
+ *
+ * @param string $id The alarm's unique id.
+ * @param string $user The alarm's user
+ * @param Horde_Date $snooze The snooze time.
+ *
+ * @throws Horde_Alarm_Exception
+ */
+ protected function _snooze($id, $user, Horde_Date $snooze)
+ {
+ $alarm = &$this->_findAlarm($id, $user);
+ $alarm['snooze'] = $snooze;
+ }
+
+ /**
+ * Returns whether an alarm is snoozed.
+ *
+ * @param string $id The alarm's unique id.
+ * @param string $user The alarm's user
+ * @param Horde_Date $time The time when the alarm may be snoozed.
+ *
+ * @return boolean True if the alarm is snoozed.
+ * @throws Horde_Alarm_Exception
+ */
+ protected function _isSnoozed($id, $user, Horde_Date $time)
+ {
+ $alarm = $this->_findAlarm($id, $user);
+ return !empty($alarm['dismissed']) ||
+ (isset($alarm['snooze']) &&
+ $alarm['snooze']->compareDateTime($time) >= 0);
+ }
+
+ /**
+ * Dismisses an alarm.
+ *
+ * @param string $id The alarm's unique id.
+ * @param string $user The alarm's user
+ *
+ * @throws Horde_Alarm_Exception
+ */
+ protected function _dismiss($id, $user)
+ {
+ $alarm = &$this->_findAlarm($id, $user);
+ $alarm['dismissed'] = true;
+ }
+
+ /**
+ * Deletes an alarm from the backend.
+ *
+ * @param string $id The alarm's unique id.
+ * @param string $user The alarm's user. All users' alarms if null.
+ *
+ * @throws Horde_Alarm_Exception
+ */
+ protected function _delete($id, $user = null)
+ {
+ $newAlarms = array();
+ foreach ($this->_alarms as &$alarm) {
+ if ($alarm['id'] != $id ||
+ (!is_null($user) && $alarm['user'] != $user)) {
+ $newAlarms[] = $alarm;
+ }
+ }
+ $this->_alarms = $newAlarms;
+ }
+
+ /**
+ * Garbage collects old alarms in the backend.
+ *
+ * @throws Horde_Alarm_Exception
+ */
+ protected function _gc()
+ {
+ }
+
+ /**
+ * Attempts to initialize the backend.
+ *
+ * @throws Horde_Alarm_Exception
+ */
+ public function initialize()
+ {
+ }
+
+ /**
+ * Converts a value from the driver's charset.
+ *
+ * @param mixed $value Value to convert.
+ *
+ * @return mixed Converted value.
+ */
+ protected function _fromDriver($value)
+ {
+ return $value;
+ }
+
+ /**
+ * Converts a value to the driver's charset.
+ *
+ * @param mixed $value Value to convert.
+ *
+ * @return mixed Converted value.
+ */
+ protected function _toDriver($value)
+ {
+ return $value;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * @author Jan Schneider <jan@horde.org>
+ * @license http://www.fsf.org/copyleft/lgpl.html LGPL
+ * @category Horde
+ * @package Horde_Alarm
+ * @subpackage UnitTests
+ */
+
+class Horde_Alarm_ObjectTest extends PHPUnit_Framework_TestCase
+{
+ protected static $alarm;
+ protected static $date;
+ protected static $end;
+
+ public function testFactory()
+ {
+ self::$alarm = Horde_Alarm::factory('Object');
+ }
+
+ /**
+ * @depends testFactory
+ */
+ public function testSet()
+ {
+ $now = time();
+ self::$date = new Horde_Date($now);
+ self::$end = new Horde_Date($now + 3600);
+ $hash = array('id' => 'personalalarm',
+ 'user' => 'john',
+ 'start' => self::$date,
+ 'end' => self::$end,
+ 'methods' => array(),
+ 'params' => array(),
+ 'title' => 'This is a personal alarm.');
+ self::$alarm->set($hash);
+ }
+
+ /**
+ * @depends testSet
+ */
+ public function testExists()
+ {
+ $this->assertTrue(self::$alarm->exists('personalalarm', 'john'));
+ }
+
+ /**
+ * @depends testExists
+ */
+ public function testGet()
+ {
+ $alarm = self::$alarm->get('personalalarm', 'john');
+ $this->assertType('array', $alarm);
+ $this->assertEquals('personalalarm', $alarm['id']);
+ $this->assertEquals('john', $alarm['user']);
+ $this->assertEquals(array(), $alarm['methods']);
+ $this->assertEquals(array(), $alarm['params']);
+ $this->assertEquals('This is a personal alarm.', $alarm['title']);
+ $this->assertNull($alarm['text']);
+ $this->assertNull($alarm['snooze']);
+ $this->assertNull($alarm['internal']);
+ $this->assertTrue($alarm['start'] instanceof Horde_Date);
+ $this->assertTrue($alarm['end'] instanceof Horde_Date);
+ $this->assertEquals(0, $alarm['start']->compareDateTime(self::$date));
+ return $alarm;
+ }
+
+ /**
+ * @depends testGet
+ */
+ public function testUpdate($alarm)
+ {
+ $alarm['title'] = 'Changed alarm text';
+ self::$alarm->set($alarm);
+ }
+
+ /**
+ * @depends testUpdate
+ */
+ public function testListAlarms()
+ {
+ self::$alarm->set(array('id' => 'publicalarm',
+ 'start' => self::$date,
+ 'end' => self::$end,
+ 'methods' => array(),
+ 'params' => array(),
+ 'title' => 'This is a public alarm.'));
+ self::$date->min--;
+ $list = self::$alarm->listAlarms('john');
+ $this->assertEquals(2, count($list));
+ $this->assertEquals('publicalarm', $list[0]['id']);
+ $this->assertEquals('personalalarm', $list[1]['id']);
+ }
+
+ /**
+ * @depends testListAlarms
+ */
+ public function testDelete()
+ {
+ self::$alarm->delete('publicalarm', '');
+ $list = self::$alarm->listAlarms('john');
+ $this->assertEquals(1, count($list));
+ $this->assertEquals('personalalarm', $list[0]['id']);
+ }
+
+ /**
+ * @depends testDelete
+ * @expectedException Horde_Alarm_Exception
+ */
+ public function testSnoozeException()
+ {
+ self::$alarm->snooze('personalalarm', 'jane', 30);
+ }
+
+ /**
+ * @depends testDelete
+ */
+ public function testSnooze()
+ {
+ self::$alarm->snooze('personalalarm', 'john', 30);
+ $this->assertTrue(self::$alarm->isSnoozed('personalalarm', 'john'));
+ $list = self::$alarm->listAlarms('john');
+ $this->assertEquals(0, count($list));
+ $list = self::$alarm->listAlarms('john', self::$end);
+ $this->assertEquals(1, count($list));
+ $this->assertEquals('personalalarm', $list[0]['id']);
+ }
+
+ /**
+ * @depends testSnooze
+ */
+ public function testAlarmWithoutEnd()
+ {
+ self::$alarm->set(array('id' => 'noend',
+ 'user' => 'john',
+ 'start' => self::$date,
+ 'methods' => array('notify'),
+ 'params' => array(),
+ 'title' => 'This is an alarm without end.'));
+ $list = self::$alarm->listAlarms('john', self::$end);
+ $this->assertEquals(2, count($list));
+ $this->assertEquals('noend', $list[0]['id']);
+ $this->assertEquals('personalalarm', $list[1]['id']);
+ }
+
+ /**
+ * @depends testAlarmWithoutEnd
+ */
+ public function testCleanUp()
+ {
+ self::$alarm->delete('noend', 'john');
+ self::$alarm->delete('personalalarm', 'john');
+ }
+}