From 33a8f0fbee75da2cbc770f64b32d452a3b949844 Mon Sep 17 00:00:00 2001 From: Gunnar Wrobel Date: Tue, 29 Sep 2009 13:53:51 +0200 Subject: [PATCH] Allow different history drivers. This still uses Horde_History as a base class. It might be better to use Horde_History_Base but I wanted to keep the API 100% intact for now. --- framework/History/lib/Horde/History.php | 304 ++++++++------------- framework/History/lib/Horde/History/Factory.php | 137 ++++++++++ framework/History/lib/Horde/History/Sql.php | 283 +++++++++++++++++++ framework/History/package.xml | 6 + .../History/test/Horde/History/InterfaceTest.php | 39 ++- 5 files changed, 568 insertions(+), 201 deletions(-) create mode 100644 framework/History/lib/Horde/History/Factory.php create mode 100644 framework/History/lib/Horde/History/Sql.php diff --git a/framework/History/lib/Horde/History.php b/framework/History/lib/Horde/History.php index d9ef516de..595388926 100644 --- a/framework/History/lib/Horde/History.php +++ b/framework/History/lib/Horde/History.php @@ -1,5 +1,23 @@ + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=History + */ + +/** + * The Autoloader allows us to omit "require/include" statements. + */ +require_once 'Horde/Autoloader.php'; + +/** * The Horde_History:: class provides a method of tracking changes in Horde * objects, stored in a SQL table. * @@ -8,32 +26,21 @@ * See the enclosed file COPYING for license information (LGPL). If you * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. * - * @author Chuck Hagenbuch - * @package Horde_History + * @category Horde + * @package History + * @author Chuck Hagenbuch + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=History */ class Horde_History { /** - * Instance object. - * - * @var Horde_History - */ - static protected $_instance; - - /** - * Pointer to a DB instance to manage the history. - * - * @var DB - */ - protected $_db; - - /** - * Handle for the current database connection, used for writing. Defaults - * to the same handle as $_db if a separate write database is not required. + * Instance cache. * - * @var DB + * @var array */ - protected $_write_db; + static protected $_instances; /** * Attempts to return a reference to a concrete History instance. @@ -42,62 +49,44 @@ class Horde_History * * This method must be invoked as: $var = History::singleton() * - * @return Horde_History The concrete Horde_History reference. - * @throws Horde_Exception - */ - static public function singleton() - { - if (!isset(self::$_instance)) { - self::$_instance = new Horde_History(); - } - - return self::$_instance; - } - - /** - * Constructor. + * @param string $driver The driver to use. * + * @return Horde_History The concrete Horde_History reference. * @throws Horde_Exception */ - public function __construct() + static public function singleton($driver = null) { global $conf; - if (empty($conf['sql']['phptype']) || ($conf['sql']['phptype'] == 'none')) { - throw new Horde_Exception(_("The History system is disabled.")); + if (empty($driver)) { + $driver = 'Sql'; } - $this->_write_db = DB::connect($conf['sql']); - - /* Set DB portability options. */ - $portability = DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS; - - if (is_a($this->_write_db, 'DB_common')) { - $write_portability = $portability; - if ($this->_write_db->phptype == 'mssql') { - $write_portability |= DB_PORTABILITY_RTRIM; + if ($driver == 'Sql') { + if (empty($conf['sql']['phptype']) + || ($conf['sql']['phptype'] == 'none')) { + throw new Horde_Exception(_("The History system is disabled.")); } - $this->_write_db->setOption('portability', $write_portability); + $params = $conf['sql']; + } else { + $params = array(); } - /* Check if we need to set up the read DB connection - * seperately. */ - if (!empty($conf['sql']['splitread'])) { - $params = array_merge($conf['sql'], $conf['sql']['read']); - $this->_db = DB::connect($params); - - /* Set DB portability options. */ - if (is_a($this->_db, 'DB_common')) { - $read_portability = $portability; - if ($this->_db->phptype == 'mssql') { - $read_portability |= DB_PORTABILITY_RTRIM; - } - $this->_db->setOption('portability', $read_portability); - } - } else { - /* Default to the same DB handle for reads. */ - $this->_db =& $this->_write_db; + if (!isset(self::$_instances[$driver])) { + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + $injector->bindFactory( + 'Horde_History', + 'Horde_History_Factory', + 'getHistory' + ); + $config = new stdClass; + $config->driver = $driver; + $config->params = $params; + $injector->setInstance('Horde_History_Config', $config); + self::$_instances[$driver] = $injector->getInstance('Horde_History'); } + + return self::$_instances[$driver]; } /** @@ -111,18 +100,21 @@ class Horde_History * 'ts' => Timestamp of the action (this will be added automatically if * it is not present). * - * @param string $guid The unique identifier of the entry to - * add to. - * @param array $attributes The hash of name => value entries that - * describe this event. - * @param boolean $replaceAction If $attributes['action'] is already - * present in the item's history log, - * update that entry instead of creating a - * new one. + * @param string $guid The unique identifier of the entry to + * add to. + * @param array $attributes The hash of name => value entries that + * describe this event. + * @param boolean $replaceAction If $attributes['action'] is already + * present in the item's history log, + * update that entry instead of creating a + * new one. + * + * @return boolean True if the operation succeeded. * * @throws Horde_Exception */ - public function log($guid, $attributes = array(), $replaceAction = false) + public function log($guid, array $attributes = array(), + $replaceAction = false) { $history = $this->getHistory($guid); @@ -133,145 +125,84 @@ class Horde_History $attributes['ts'] = time(); } - /* If we want to replace an entry with the same action, try and find - * one. Track whether or not we succeed in $done, so we know whether - * or not to add the entry later. */ - $done = false; - if ($replaceAction && !empty($attributes['action'])) { - for ($i = 0, $count = count($history->data); $i < $count; ++$i) { - if (!empty($history->data[$i]['action']) && - $history->data[$i]['action'] == $attributes['action']) { - $values = array( - $attributes['ts'], - $attributes['who'], - isset($attributes['desc']) ? $attributes['desc'] : null - ); - - unset($attributes['ts'], $attributes['who'], $attributes['desc'], $attributes['action']); - - $values[] = $attributes - ? serialize($attributes) - : null; - $values[] = $history->data[$i]['id']; - - $r = $this->_write_db->query( - 'UPDATE horde_histories SET history_ts = ?,' . - ' history_who = ?,' . - ' history_desc = ?,' . - ' history_extra = ? WHERE history_id = ?', $values - ); - - if ($r instanceof PEAR_Error) { - Horde::logMessage($r, __FILE__, __LINE__, PEAR_LOG_ERR); - throw new Horde_Exception($r->getMessage()); - } - $done = true; - break; - } - } - } - - /* If we're not replacing by action, or if we didn't find an entry to - * replace, insert a new row. */ - if (!$done) { - $history_id = $this->_write_db->nextId('horde_histories'); - if ($history_id instanceof PEAR_Error) { - Horde::logMessage($history_id, __FILE__, __LINE__, PEAR_LOG_ERR); - throw new Horde_Exception($history_id->getMessage()); - } - - $values = array( - $history_id, - $guid, - $attributes['ts'], - $attributes['who'], - isset($attributes['desc']) ? $attributes['desc'] : null, - isset($attributes['action']) ? $attributes['action'] : null - ); - - unset($attributes['ts'], $attributes['who'], $attributes['desc'], $attributes['action']); - - $values[] = $attributes - ? serialize($attributes) - : null; - - $r = $this->_write_db->query( - 'INSERT INTO horde_histories (history_id, object_uid, history_ts, history_who, history_desc, history_action, history_extra)' . - ' VALUES (?, ?, ?, ?, ?, ?, ?)', $values - ); - - if ($r instanceof PEAR_Error) { - Horde::logMessage($r, __FILE__, __LINE__, PEAR_LOG_ERR); - throw new Horde_Exception($r->getMessage()); - } - } + return $this->_log($history, $attributes, $replaceAction); + } - return true; + /** + * Logs an event to an item's history log. Any other details about the event + * are passed in $attributes. + * + * @param Horde_HistoryObject $history The history item to add to. + * @param array $attributes The hash of name => value entries + * that describe this event. + * @param boolean $replaceAction If $attributes['action'] is + * already present in the item's + * history log, update that entry + * instead of creating a new one. + * + * @return boolean True if the operation succeeded. + * + * @throws Horde_Exception + */ + protected function _log(Horde_HistoryObject $history, array $attributes, + $replaceAction = false) + { + throw new Horde_Exception('Not implemented!'); } /** * Returns a Horde_HistoryObject corresponding to the named history * entry, with the data retrieved appropriately. * - * @param string $guid The name of the history entry to retrieve. + * @param string $guid The name of the history entry to retrieve. + * + * @return Horde_HistoryObject A Horde_HistoryObject * - * @return Horde_HistoryObject A Horde_HistoryObject + * @throws Horde_Exception */ public function getHistory($guid) { - $rows = $this->_db->getAll('SELECT * FROM horde_histories WHERE object_uid = ?', array($guid), DB_FETCHMODE_ASSOC); - return new Horde_HistoryObject($guid, $rows); + throw new Horde_Exception('Not implemented!'); } /** * Finds history objects by timestamp, and optionally filter on other * fields as well. * - * @param string $cmp The comparison operator (<, >, <=, >=, or =) to - * check the timestamps with. - * @param integer $ts The timestamp to compare against. - * @param array $filters An array of additional (ANDed) criteria. - * Each array value should be an array with 3 - * entries: + * @param string $cmp The comparison operator (<, >, <=, >=, or =) to + * check the timestamps with. + * @param integer $ts The timestamp to compare against. + * @param array $filters An array of additional (ANDed) criteria. + * Each array value should be an array with 3 + * entries: *
      * 'field' - the history field being compared (i.e. 'action').
      * 'op'    - the operator to compare this field with.
      * 'value' - the value to check for (i.e. 'add').
      * 
- * @param string $parent The parent history to start searching at. If - * non-empty, will be searched for with a LIKE - * '$parent:%' clause. + * @param string $parent The parent history to start searching at. If + * non-empty, will be searched for with a LIKE + * '$parent:%' clause. * * @return array An array of history object ids, or an empty array if * none matched the criteria. + * + * @throws Horde_Exception */ - public function getByTimestamp($cmp, $ts, $filters = array(), + public function getByTimestamp($cmp, $ts, array $filters = array(), $parent = null) { - /* Build the timestamp test. */ - $where = array("history_ts $cmp $ts"); - - /* Add additional filters, if there are any. */ - if ($filters) { - foreach ($filters as $filter) { - $where[] = 'history_' . $filter['field'] . ' ' . $filter['op'] . ' ' . $this->_db->quote($filter['value']); - } - } - - if ($parent) { - $where[] = 'object_uid LIKE ' . $this->_db->quote($parent . ':%'); - } - - return $this->_db->getAssoc('SELECT DISTINCT object_uid, history_id FROM horde_histories WHERE ' . implode(' AND ', $where)); + throw new Horde_Exception('Not implemented!'); } /** * Gets the timestamp of the most recent change to $guid. * - * @param string $guid The name of the history entry to retrieve. - * @param string $action An action: 'add', 'modify', 'delete', etc. + * @param string $guid The name of the history entry to retrieve. + * @param string $action An action: 'add', 'modify', 'delete', etc. * * @return integer The timestamp, or 0 if no matching entry is found. + * * @throws Horde_Exception */ public function getActionTimestamp($guid, $action) @@ -301,20 +232,15 @@ class Horde_History /** * Remove one or more history entries by name. * - * @param array $names The history entries to remove. + * @param array $names The history entries to remove. + * + * @return boolean True if the operation succeeded. + * + * @throws Horde_Exception */ - public function removeByNames($names) + public function removeByNames(array $names) { - if (!count($names)) { - return true; - } - - $ids = array(); - foreach ($names as $name) { - $ids[] = $this->_write_db->quote($name); - } - - return $this->_write_db->query('DELETE FROM horde_histories WHERE object_uid IN (' . implode(',', $ids) . ')'); + throw new Horde_Exception('Not implemented!'); } } diff --git a/framework/History/lib/Horde/History/Factory.php b/framework/History/lib/Horde/History/Factory.php new file mode 100644 index 000000000..c475912f8 --- /dev/null +++ b/framework/History/lib/Horde/History/Factory.php @@ -0,0 +1,137 @@ + + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=History + */ + +/** + * The Autoloader allows us to omit "require/include" statements. + */ +require_once 'Horde/Autoloader.php'; + +/** + * The Horde_History_Factory:: provides a method for generating + * a Horde_History handler. + * + * Copyright 2003-2009 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. + * + * @category Horde + * @package History + * @author Chuck Hagenbuch + * @author Gunnar Wrobel + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=History + */ +class Horde_History_Factory +{ + /** + * Create a concrete Horde_History instance. + * + * @param Horde_Injector $injector The environment for creating the instance. + * + * @return Horde_History The new Horde_History instance. + * + * @throws Horde_Exception If the injector provides no configuration. + */ + static public function getHistory(Horde_Injector $injector) + { + try { + $config = $injector->getInstance('Horde_History_Config'); + } catch (ReflectionException $e) { + throw new Horde_Exception( + sprintf( + 'The configuration for the History driver is missing: %s', + $e->getMessage() + ) + ); + } + + switch (ucfirst($config->driver)) { + case 'Sql': + return Horde_History_Factory::getHistorySql($injector, $config->params); + case 'Mock': + default: + return Horde_History_Factory::getHistoryMock($config->params); + } + } + + /** + * Create a concrete Horde_History_Sql instance. + * + * @param Horde_Injector $injector The environment for creating the instance. + * @param array $params The db connection parameters if the + * environment does not already provide a + * connection. + * + * @return Horde_History_Sql The new Horde_History_Sql instance. + * + * @throws Horde_Exception If the injector provides no configuration or + * creating the database connection failed. + */ + static protected function getHistorySql(Horde_Injector $injector, array $params) + { + try { + /** See if there is a specific write db instance available */ + $write_db = $injector->getInstance('DB_common_write'); + $history = new Horde_History_Sql($write_db); + try { + /** See if there is a specific read db instance available */ + $read_db = $injector->getInstance('DB_common_read'); + $history->setReadDb($read_db); + } catch (ReflectionException $e) { + } + } catch (ReflectionException $e) { + /** No DB instances. Use the configuration. */ + $write_db = Horde_History_Factory::getDb($params); + + $history = new Horde_History_Sql($write_db); + + /* Check if we need to set up the read DB connection + * seperately. */ + if (!empty($params['splitread'])) { + $params = array_merge($params, $params['read']); + $read_db = Horde_History_Factory::getDb($params); + $history->setReadDb($read_db); + } + } + return $history; + } + + /** + * Create a database connection. + * + * @param array $params The database connection parameters. + * + * @return DB_common + * + * @throws Horde_Exception In case the database connection failed. + */ + static protected function getDb(array $params) + { + $db = DB::connect($params); + + /* Set DB portability options. */ + $portability = DB_PORTABILITY_LOWERCASE | DB_PORTABILITY_ERRORS; + + if ($db instanceOf DB_common) { + if ($db->phptype == 'mssql') { + $portability |= DB_PORTABILITY_RTRIM; + } + $db->setOption('portability', $portability); + } else if ($db instanceOf PEAR_Error) { + throw new Horde_Exception($db->getMessage()); + } + return $db; + } +} \ No newline at end of file diff --git a/framework/History/lib/Horde/History/Sql.php b/framework/History/lib/Horde/History/Sql.php new file mode 100644 index 000000000..91bdd6288 --- /dev/null +++ b/framework/History/lib/Horde/History/Sql.php @@ -0,0 +1,283 @@ + + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=History + */ + +/** + * The Horde_History_Sql:: class provides a method of tracking changes in Horde + * objects, stored in a SQL table. + * + * Copyright 2003-2009 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. + * + * @category Horde + * @package History + * @author Chuck Hagenbuch + * @license http://www.fsf.org/copyleft/lgpl.html LGPL + * @link http://pear.horde.org/index.php?package=History + */ +class Horde_History_Sql extends Horde_History +{ + /** + * Pointer to a DB instance to manage the history. + * + * @var DB + */ + protected $_db; + + /** + * Handle for the current database connection, used for writing. Defaults + * to the same handle as $_db if a separate write database is not required. + * + * @var DB + */ + protected $_write_db; + + /** + * Constructor. + * + * @param DB_common $db The database connection. + */ + public function __construct(DB_common $db) + { + $this->_write_db = $db; + $this->_db = $db; + } + + /** + * Set a separate read database connection if you want to split read and + * write access to the db. + * + * @param DB_common $db The database connection. + * + * @return NULL + */ + public function setReadDb(DB_common $db) + { + $this->_db = $db; + } + + /** + * Logs an event to an item's history log. Any other details about the event + * are passed in $attributes. + * + * @param Horde_HistoryObject $history The history item to add to. + * @param array $attributes The hash of name => value entries + * that describe this event. + * @param boolean $replaceAction If $attributes['action'] is + * already present in the item's + * history log, update that entry + * instead of creating a new one. + * + * @return boolean True if the operation succeeded. + * + * @throws Horde_Exception + */ + protected function _log(Horde_HistoryObject $history, + array $attributes, + $replaceAction = false) + { + /* If we want to replace an entry with the same action, try and find + * one. Track whether or not we succeed in $done, so we know whether + * or not to add the entry later. */ + $done = false; + if ($replaceAction && !empty($attributes['action'])) { + for ($i = 0, $count = count($history->data); $i < $count; ++$i) { + if (!empty($history->data[$i]['action']) && + $history->data[$i]['action'] == $attributes['action']) { + $values = array( + $attributes['ts'], + $attributes['who'], + isset($attributes['desc']) ? $attributes['desc'] : null + ); + + unset($attributes['ts'], $attributes['who'], + $attributes['desc'], $attributes['action']); + + $values[] = $attributes + ? serialize($attributes) + : null; + $values[] = $history->data[$i]['id']; + + $r = $this->_write_db->query( + 'UPDATE horde_histories SET history_ts = ?,' . + ' history_who = ?,' . + ' history_desc = ?,' . + ' history_extra = ? WHERE history_id = ?', $values + ); + + if ($r instanceof PEAR_Error) { + Horde::logMessage($r, __FILE__, __LINE__, PEAR_LOG_ERR); + throw new Horde_Exception($r->getMessage()); + } + $done = true; + break; + } + } + } + + /* If we're not replacing by action, or if we didn't find an entry to + * replace, insert a new row. */ + if (!$done) { + $history_id = $this->_write_db->nextId('horde_histories'); + if ($history_id instanceof PEAR_Error) { + Horde::logMessage($history_id, __FILE__, __LINE__, PEAR_LOG_ERR); + throw new Horde_Exception($history_id->getMessage()); + } + + $values = array( + $history_id, + $history->uid, + $attributes['ts'], + $attributes['who'], + isset($attributes['desc']) ? $attributes['desc'] : null, + isset($attributes['action']) ? $attributes['action'] : null + ); + + unset($attributes['ts'], $attributes['who'], + $attributes['desc'], $attributes['action']); + + $values[] = $attributes + ? serialize($attributes) + : null; + + $r = $this->_write_db->query( + 'INSERT INTO horde_histories (history_id, object_uid, history_ts, history_who, history_desc, history_action, history_extra)' . + ' VALUES (?, ?, ?, ?, ?, ?, ?)', $values + ); + + if ($r instanceof PEAR_Error) { + Horde::logMessage($r, __FILE__, __LINE__, PEAR_LOG_ERR); + throw new Horde_Exception($r->getMessage()); + } + } + + return true; + } + + /** + * Returns a Horde_HistoryObject corresponding to the named history + * entry, with the data retrieved appropriately. + * + * @param string $guid The name of the history entry to retrieve. + * + * @return Horde_HistoryObject A Horde_HistoryObject + */ + public function getHistory($guid) + { + $rows = $this->_db->getAll('SELECT * FROM horde_histories WHERE object_uid = ?', array($guid), DB_FETCHMODE_ASSOC); + return new Horde_HistoryObject($guid, $rows); + } + + /** + * Finds history objects by timestamp, and optionally filter on other + * fields as well. + * + * @param string $cmp The comparison operator (<, >, <=, >=, or =) to + * check the timestamps with. + * @param integer $ts The timestamp to compare against. + * @param array $filters An array of additional (ANDed) criteria. + * Each array value should be an array with 3 + * entries: + *
+     * 'field' - the history field being compared (i.e. 'action').
+     * 'op'    - the operator to compare this field with.
+     * 'value' - the value to check for (i.e. 'add').
+     * 
+ * @param string $parent The parent history to start searching at. If + * non-empty, will be searched for with a LIKE + * '$parent:%' clause. + * + * @return array An array of history object ids, or an empty array if + * none matched the criteria. + * + * @throws Horde_Exception + */ + public function getByTimestamp($cmp, $ts, $filters = array(), + $parent = null) + { + /* Build the timestamp test. */ + $where = array("history_ts $cmp $ts"); + + /* Add additional filters, if there are any. */ + if ($filters) { + foreach ($filters as $filter) { + $where[] = 'history_' . $filter['field'] . ' ' . $filter['op'] . ' ' . $this->_db->quote($filter['value']); + } + } + + if ($parent) { + $where[] = 'object_uid LIKE ' . $this->_db->quote($parent . ':%'); + } + + return $this->_db->getAssoc('SELECT DISTINCT object_uid, history_id FROM horde_histories WHERE ' . implode(' AND ', $where)); + } + + /** + * Gets the timestamp of the most recent change to $guid. + * + * @param string $guid The name of the history entry to retrieve. + * @param string $action An action: 'add', 'modify', 'delete', etc. + * + * @return integer The timestamp, or 0 if no matching entry is found. + * + * @throws Horde_Exception + */ + public function getActionTimestamp($guid, $action) + { + /* This implementation still works, but we should be able to + * get much faster now with a SELECT MAX(history_ts) + * ... query. */ + try { + $history = $this->getHistory($guid); + } catch (Horde_Exception $e) { + return 0; + } + + $last = 0; + + if (is_array($history->data)) { + foreach ($history->data as $entry) { + if (($entry['action'] == $action) && ($entry['ts'] > $last)) { + $last = $entry['ts']; + } + } + } + + return (int)$last; + } + + /** + * Remove one or more history entries by name. + * + * @param array $names The history entries to remove. + * + * @return boolean True if the operation succeeded. + * + * @throws Horde_Exception + */ + public function removeByNames($names) + { + if (!count($names)) { + return true; + } + + $ids = array(); + foreach ($names as $name) { + $ids[] = $this->_write_db->quote($name); + } + + return $this->_write_db->query('DELETE FROM horde_histories WHERE object_uid IN (' . implode(',', $ids) . ')'); + } + +} diff --git a/framework/History/package.xml b/framework/History/package.xml index 53fa4af49..f31f2c512 100644 --- a/framework/History/package.xml +++ b/framework/History/package.xml @@ -32,6 +32,10 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + + + @@ -62,6 +66,8 @@ http://pear.php.net/dtd/package-2.0.xsd"> + + diff --git a/framework/History/test/Horde/History/InterfaceTest.php b/framework/History/test/Horde/History/InterfaceTest.php index e9491b196..b37e71d93 100644 --- a/framework/History/test/Horde/History/InterfaceTest.php +++ b/framework/History/test/Horde/History/InterfaceTest.php @@ -44,11 +44,9 @@ class Horde_History_InterfaceTest extends PHPUnit_Framework_TestCase */ private $_db_file; - - public function setUp() - { - } - + /** + * Test cleanup. + */ public function tearDown() { if (!empty($this->_db_file)) { @@ -64,7 +62,10 @@ class Horde_History_InterfaceTest extends PHPUnit_Framework_TestCase public function getEnvironments() { if (empty($this->_environments)) { - /** The db environment provides our only test scenario before refactoring */ + /** + * The db environment provides our only test scenario before + * refactoring. + */ $this->_environments = array(self::ENVIRONMENT_DB); } return $this->_environments; @@ -123,7 +124,19 @@ EOL; $conf['sql']['charset'] = 'utf-8'; $conf['sql']['phptype'] = 'sqlite'; - $history = new Horde_History(); + $injector = new Horde_Injector(new Horde_Injector_TopLevel()); + $injector->bindFactory( + 'Horde_History', + 'Horde_History_Factory', + 'getHistory' + ); + + $config = new stdClass; + $config->driver = 'Sql'; + $config->params = $conf['sql']; + $injector->setInstance('Horde_History_Config', $config); + + $history = $injector->getInstance('Horde_History'); break; } } @@ -137,7 +150,9 @@ EOL; foreach ($this->getEnvironments() as $environment) { $history = $this->getHistory($environment); $history1 = Horde_History::singleton(); + $this->assertType('Horde_History', $history1); $history2 = Horde_History::singleton(); + $this->assertType('Horde_History', $history2); $this->assertSame($history1, $history2); } } @@ -149,7 +164,7 @@ EOL; $history = $this->getHistory($environment); $history->log('test', array('action' => 'test')); $this->assertTrue($history->getActionTimestamp('test', 'test') > 0); - $data = $history->getHistory('test')->getData(); + $data = $history->getHistory('test')->getData(); $this->assertTrue(isset($data[0]['who'])); } } @@ -236,7 +251,7 @@ EOL; 'who' => 'you', 'id' => 2, 'ts' => 2000, - 'extra' => array('a' => 'a'), + 'extra' => array('a' => 'a'), ), ); $this->assertEquals($expect, $data); @@ -257,7 +272,7 @@ EOL; $history = $this->getHistory($environment); $history->log('test', array('who' => 'me', 'ts' => 1000, 'action' => 'test')); $history->log('test', array('who' => 'you', 'ts' => 2000, 'action' => 'yours', 'extra' => array('a' => 'a'))); - $result = $history->getByTimestamp('>', 1, array(array('field' => 'who', 'op' => '=', 'value' => 'you'))); + $result = $history->getByTimestamp('>', 1, array(array('field' => 'who', 'op' => '=', 'value' => 'you'))); $this->assertEquals(array('test' => 2), $result); } } @@ -269,7 +284,7 @@ EOL; $history->log('test:a', array('who' => 'me', 'ts' => 1000, 'action' => 'test')); $history->log('test:b', array('who' => 'you', 'ts' => 2000, 'action' => 'yours')); $history->log('yours', array('who' => 'you', 'ts' => 3000, 'action' => 'yours')); - $result = $history->getByTimestamp('>', 1, array(), 'test'); + $result = $history->getByTimestamp('>', 1, array(), 'test'); $this->assertEquals(array('test:a' => 1, 'test:b' => 2), $result); } } @@ -281,7 +296,7 @@ EOL; $history = $this->getHistory($environment); $history->log('test', array('who' => 'me', 'ts' => 1000, 'action' => 'test')); $history->log('test', array('who' => 'you', 'ts' => 2000, 'action' => 'yours', 'extra' => array('a' => 'a'))); - $result = $history->getByTimestamp('<', 1001); + $result = $history->getByTimestamp('<', 1001); $this->assertEquals(array('test' => 1), $result); } } -- 2.11.0