509 lines
18 KiB
PHP
509 lines
18 KiB
PHP
<?php
|
|
/**
|
|
* Copyright 2007-2017 Horde LLC (http://www.horde.org/)
|
|
*
|
|
* See the enclosed file COPYING for license information (LGPL). If you
|
|
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
|
|
*
|
|
* @author Jan Schneider <jan@horde.org>
|
|
* @category Horde
|
|
* @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
|
|
* @package Alarm
|
|
*/
|
|
|
|
/**
|
|
* The Horde_Alarm_Sql class is a Horde_Alarm storage implementation using the
|
|
* Horde Db package.
|
|
*
|
|
* The table structure can be created by the migration script.
|
|
*
|
|
* @author Jan Schneider <jan@horde.org>
|
|
* @category Horde
|
|
* @copyright 2007-2017 Horde LLC
|
|
* @license http://www.horde.org/licenses/lgpl21 LGPL-2.1
|
|
* @package Alarm
|
|
*/
|
|
class Horde_Alarm_Sql extends Horde_Alarm
|
|
{
|
|
/**
|
|
* Handle for the current database connection.
|
|
*
|
|
* @var Horde_Db_Adapter
|
|
*/
|
|
protected $_db;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param array $params Configuration parameters:
|
|
* <pre>
|
|
* 'db' - (Horde_Db_Adapter) [REQUIRED] The DB instance.
|
|
* 'table' - (string) The name of the alarm table in 'database'.
|
|
* DEFAULT: 'horde_alarms'
|
|
* </pre>
|
|
*
|
|
* @throws Horde_Alarm_Exception
|
|
*/
|
|
public function __construct(array $params = array())
|
|
{
|
|
if (!isset($params['db'])) {
|
|
throw new Horde_Alarm_Exception('Missing db parameter.');
|
|
}
|
|
$this->_db = $params['db'];
|
|
unset($params['db']);
|
|
|
|
$params = array_merge(array(
|
|
'table' => 'horde_alarms'
|
|
), $params);
|
|
|
|
parent::__construct($params);
|
|
}
|
|
|
|
/**
|
|
* Returns a list of alarms from the backend.
|
|
*
|
|
* @param string $user Return alarms for this user, all users if
|
|
* null, or global alarms if empty.
|
|
* @param Horde_Date $time The time when the alarms should be active.
|
|
*
|
|
* @return array A list of alarm hashes.
|
|
* @throws Horde_Alarm_Exception
|
|
*/
|
|
protected function _list($user, Horde_Date $time)
|
|
{
|
|
$query = sprintf('SELECT alarm_id, alarm_uid, alarm_start, alarm_end, alarm_methods, alarm_params, alarm_title, alarm_text, alarm_snooze, alarm_internal FROM %s WHERE alarm_dismissed = 0 AND ((alarm_snooze IS NULL AND alarm_start <= ?) OR alarm_snooze <= ?) AND (alarm_end IS NULL OR alarm_end >= ?)%s ORDER BY alarm_start, alarm_end',
|
|
$this->_params['table'],
|
|
is_null($user) ? '' : ' AND (alarm_uid IS NULL OR alarm_uid = ? OR alarm_uid = ?)');
|
|
$dt = $time->setTimezone('UTC')->format(Horde_Date::DATE_DEFAULT);
|
|
$values = array($dt, $dt, $dt);
|
|
if (!is_null($user)) {
|
|
$values[] = '';
|
|
$values[] = (string)$user;
|
|
}
|
|
|
|
$alarms = array();
|
|
try {
|
|
$result = $this->_db->select($query, $values);
|
|
foreach ($result as $val) {
|
|
$alarms[] = $this->_getHash($val);
|
|
}
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
|
|
return $alarms;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of all global alarms from the backend.
|
|
*
|
|
* @return array A list of alarm hashes.
|
|
* @throws Horde_Alarm_Exception
|
|
*/
|
|
protected function _global()
|
|
{
|
|
$query = sprintf('SELECT alarm_id, alarm_uid, alarm_start, alarm_end, alarm_methods, alarm_params, alarm_title, alarm_text, alarm_snooze, alarm_internal FROM %s WHERE alarm_uid IS NULL OR alarm_uid = \'\' ORDER BY alarm_start, alarm_end',
|
|
$this->_params['table']);
|
|
|
|
try {
|
|
$result = $this->_db->select($query);
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
|
|
$alarms = array();
|
|
foreach ($result as $val) {
|
|
$alarms[] = $this->_getHash($val);
|
|
}
|
|
|
|
return $alarms;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
protected function _getHash(array $alarm)
|
|
{
|
|
foreach (array('params', 'text', 'internal') as $column) {
|
|
if (isset($alarm['alarm_' . $column])) {
|
|
$alarm['alarm_' . $column] = $this->_convertBinary(
|
|
'alarm_' . $column,
|
|
$alarm['alarm_' . $column]
|
|
);
|
|
}
|
|
}
|
|
$params = base64_decode($alarm['alarm_params']);
|
|
if (!strlen($params) && strlen($alarm['alarm_params'])) {
|
|
$params = $alarm['alarm_params'];
|
|
}
|
|
|
|
try {
|
|
$params = @unserialize($params);
|
|
} catch (Exception $e) {
|
|
$params = array();
|
|
}
|
|
|
|
$internal = null;
|
|
if (!empty($alarm['alarm_internal'])) {
|
|
try {
|
|
$internal = @unserialize($alarm['alarm_internal']);
|
|
} catch (Exception $e) {}
|
|
}
|
|
|
|
return array(
|
|
'id' => $alarm['alarm_id'],
|
|
'user' => $alarm['alarm_uid'],
|
|
'start' => new Horde_Date($alarm['alarm_start'], 'UTC'),
|
|
'end' => empty($alarm['alarm_end']) ? null : new Horde_Date($alarm['alarm_end'], 'UTC'),
|
|
'methods' => @unserialize($alarm['alarm_methods']),
|
|
'params' => $params,
|
|
'title' => $this->_fromDriver($alarm['alarm_title']),
|
|
'text' => $this->_fromDriver($alarm['alarm_text']),
|
|
'snooze' => empty($alarm['alarm_snooze']) ? null : new Horde_Date($alarm['alarm_snooze'], 'UTC'),
|
|
'internal' => $internal
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
$query = sprintf(
|
|
'SELECT alarm_id, alarm_uid, alarm_start, alarm_end, alarm_methods, alarm_params, alarm_title, alarm_text, alarm_snooze, alarm_internal FROM %s WHERE alarm_id = ? AND %s',
|
|
$this->_params['table'],
|
|
!empty($user) ? 'alarm_uid = ?' : '(alarm_uid = ? OR alarm_uid IS NULL)'
|
|
);
|
|
|
|
try {
|
|
$alarm = $this->_db->selectOne($query, array($id, $user));
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
|
|
if (empty($alarm)) {
|
|
throw new Horde_Alarm_Exception('Alarm not found');
|
|
}
|
|
|
|
return $this->_getHash($alarm);
|
|
}
|
|
|
|
/**
|
|
* Adds an alarm hash to the backend.
|
|
*
|
|
* @param array $alarm An alarm hash.
|
|
*
|
|
* @throws Horde_Alarm_Exception
|
|
*/
|
|
protected function _add(array $alarm)
|
|
{
|
|
$values = array(
|
|
'alarm_id' => $alarm['id'],
|
|
'alarm_uid' => isset($alarm['user']) ? $alarm['user'] : '',
|
|
'alarm_start' => $alarm['start']->setTimezone('UTC')->format(Horde_Date::DATE_DEFAULT),
|
|
'alarm_end' => empty($alarm['end']) ? null : $alarm['end']->setTimezone('UTC')->format(Horde_Date::DATE_DEFAULT),
|
|
'alarm_methods' => serialize($alarm['methods']),
|
|
'alarm_params' => new Horde_Db_Value_Text(base64_encode(serialize($alarm['params']))),
|
|
'alarm_title' => $this->_toDriver($alarm['title']),
|
|
'alarm_text' => empty($alarm['text']) ? null : new Horde_Db_Value_Text($this->_toDriver($alarm['text'])),
|
|
'alarm_snooze' => null,
|
|
'alarm_instanceid' => empty($alarm['instanceid']) ? null : $alarm['instanceid']
|
|
);
|
|
|
|
try {
|
|
$this->_db->insertBlob($this->_params['table'], $values);
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates an alarm hash in the backend.
|
|
*
|
|
* @param array $alarm An alarm hash.
|
|
* @param boolean $keepsnooze Whether to keep the snooze value unchanged.
|
|
*
|
|
* @throws Horde_Alarm_Exception
|
|
*/
|
|
protected function _update(array $alarm, $keepsnooze = false)
|
|
{
|
|
$where = array(
|
|
sprintf(
|
|
'alarm_id = ? AND %s',
|
|
isset($alarm['user']) ? 'alarm_uid = ?' : '(alarm_uid = ? OR alarm_uid IS NULL)'
|
|
),
|
|
array(
|
|
$alarm['id'],
|
|
isset($alarm['user']) ? $alarm['user'] : ''
|
|
)
|
|
);
|
|
$values = array(
|
|
'alarm_start' => $alarm['start']->setTimezone('UTC')->format(Horde_Date::DATE_DEFAULT),
|
|
'alarm_end' => empty($alarm['end']) ? null : $alarm['end']->setTimezone('UTC')->format(Horde_Date::DATE_DEFAULT),
|
|
'alarm_methods' => serialize($alarm['methods']),
|
|
'alarm_params' => new Horde_Db_Value_Text(base64_encode(serialize($alarm['params']))),
|
|
'alarm_title' => $this->_toDriver($alarm['title']),
|
|
'alarm_instanceid' => empty($alarm['instanceid']) ? null : $alarm['instanceid'],
|
|
'alarm_text' => empty($alarm['text']) ? null : new Horde_Db_Value_Text($this->_toDriver($alarm['text']))
|
|
);
|
|
if (!$keepsnooze) {
|
|
$values['alarm_snooze'] = null;
|
|
$values['alarm_dismissed'] = 0;
|
|
}
|
|
|
|
try {
|
|
$this->_db->updateBlob($this->_params['table'], $values, $where);
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
*/
|
|
public function internal($id, $user, array $internal)
|
|
{
|
|
$query = sprintf('UPDATE %s set alarm_internal = ? WHERE alarm_id = ? AND %s',
|
|
$this->_params['table'],
|
|
!empty($user) ? 'alarm_uid = ?' : '(alarm_uid = ? OR alarm_uid IS NULL)');
|
|
$values = array(new Horde_Db_Value_Text(serialize($internal)), $id, $user);
|
|
|
|
try {
|
|
$this->_db->update($query, $values);
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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
|
|
* @param string $instanceid An optional instanceid to match.
|
|
*
|
|
* @return boolean True if the specified alarm exists.
|
|
* @throws Horde_Alarm_Exception
|
|
*/
|
|
protected function _exists($id, $user, $instanceid = null)
|
|
{
|
|
$query = sprintf('SELECT 1 FROM %s WHERE alarm_id = ? AND %s',
|
|
$this->_params['table'],
|
|
(!empty($user) ? 'alarm_uid = ?' : '(alarm_uid = ? OR alarm_uid IS NULL)')
|
|
. (!empty($instanceid) ? ' AND alarm_instanceid = ?' : ''));
|
|
$params = array($id, $user);
|
|
if (!empty($instanceid)) {
|
|
$params[] = $instanceid;
|
|
}
|
|
|
|
try {
|
|
return ($this->_db->selectValue($query, $params) == 1);
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
$query = sprintf('UPDATE %s set alarm_snooze = ? WHERE alarm_id = ? AND %s',
|
|
$this->_params['table'],
|
|
!empty($user) ? 'alarm_uid = ?' : '(alarm_uid = ? OR alarm_uid IS NULL)');
|
|
$values = array($snooze->setTimezone('UTC')->format(Horde_Date::DATE_DEFAULT), $id, $user);
|
|
|
|
try {
|
|
$this->_db->update($query, $values);
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
$query = sprintf('SELECT 1 FROM %s WHERE alarm_id = ? AND %s AND (alarm_dismissed = 1 OR (alarm_snooze IS NOT NULL AND alarm_snooze >= ?))',
|
|
$this->_params['table'],
|
|
!empty($user) ? 'alarm_uid = ?' : '(alarm_uid = ? OR alarm_uid IS NULL)');
|
|
|
|
try {
|
|
return $this->_db->selectValue($query, array($id, $user, $time->setTimezone('UTC')->format(Horde_Date::DATE_DEFAULT)));
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
$query = sprintf('UPDATE %s set alarm_dismissed = 1 WHERE alarm_id = ? AND %s',
|
|
$this->_params['table'],
|
|
!empty($user) ? 'alarm_uid = ?' : '(alarm_uid = ? OR alarm_uid IS NULL)');
|
|
$values = array($id, $user);
|
|
|
|
try {
|
|
$this->_db->update($query, $values);
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
{
|
|
$query = sprintf('DELETE FROM %s WHERE alarm_id = ?', $this->_params['table']);
|
|
$values = array($id);
|
|
if (!is_null($user)) {
|
|
$query .= empty($user)
|
|
? ' AND (alarm_uid IS NULL OR alarm_uid = ?)'
|
|
: ' AND alarm_uid = ?';
|
|
$values[] = $user;
|
|
}
|
|
|
|
try {
|
|
$this->_db->delete($query, $values);
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Garbage collects old alarms in the backend.
|
|
*/
|
|
protected function _gc()
|
|
{
|
|
$query = sprintf('DELETE FROM %s WHERE alarm_end IS NOT NULL AND alarm_end < ?', $this->_params['table']);
|
|
$end = new Horde_Date(time());
|
|
$this->_db->delete($query, array($end->setTimezone('UTC')->format(Horde_Date::DATE_DEFAULT)));
|
|
}
|
|
|
|
/**
|
|
* Initialization tasks.
|
|
*
|
|
* @throws Horde_Alarm_Exception
|
|
*/
|
|
public function initialize()
|
|
{
|
|
/* Handle any database specific initialization code to run. */
|
|
switch ($this->_db->adapterName()) {
|
|
case 'PDO_Oci':
|
|
$query = "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'";
|
|
$this->_db->select($query);
|
|
break;
|
|
|
|
case 'PDO_PostgreSQL':
|
|
$query = "SET datestyle TO 'iso'";
|
|
$this->_db->select($query);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Converts a value from the driver's charset.
|
|
*
|
|
* @param mixed $value Value to convert.
|
|
*
|
|
* @return mixed Converted value.
|
|
*/
|
|
protected function _fromDriver($value)
|
|
{
|
|
return Horde_String::convertCharset($value, $this->_params['charset'], 'UTF-8');
|
|
}
|
|
|
|
/**
|
|
* Converts a value to the driver's charset.
|
|
*
|
|
* @param mixed $value Value to convert.
|
|
*
|
|
* @return mixed Converted value.
|
|
*/
|
|
protected function _toDriver($value)
|
|
{
|
|
return Horde_String::convertCharset($value, 'UTF-8', $this->_params['charset']);
|
|
}
|
|
|
|
/**
|
|
* Converts results from TEXT columns to strings.
|
|
*
|
|
* @param string $column A column name.
|
|
* @param mixed $value A TEXT column value.
|
|
*
|
|
* @return string The column value as plain string.
|
|
*/
|
|
protected function _convertBinary($column, $value)
|
|
{
|
|
try {
|
|
$columns = $this->_db->columns($this->_params['table']);
|
|
} catch (Horde_Db_Exception $e) {
|
|
throw new Horde_Alarm_Exception(
|
|
Horde_Alarm_Translation::t("Server error when querying database.")
|
|
);
|
|
}
|
|
return $columns[$column]->binaryToString($value);
|
|
}
|
|
}
|