1: <?php
2: /**
3: * The Horde_History:: system.
4: *
5: * PHP version 5
6: *
7: * @category Horde
8: * @package History
9: * @author Chuck Hagenbuch <chuck@horde.org>
10: * @author Gunnar Wrobel <wrobel@pardus.de>
11: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
12: * @link http://pear.horde.org/index.php?package=History
13: */
14:
15: /**
16: * The Horde_History:: class provides a method of tracking changes in Horde
17: * objects, stored in a SQL table.
18: *
19: * Copyright 2003-2012 Horde LLC (http://www.horde.org/)
20: *
21: * See the enclosed file COPYING for license information (LGPL). If you
22: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
23: *
24: * @category Horde
25: * @package History
26: * @author Chuck Hagenbuch <chuck@horde.org>
27: * @author Gunnar Wrobel <wrobel@pardus.de>
28: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
29: * @link http://pear.horde.org/index.php?package=History
30: */
31: abstract class Horde_History
32: {
33: /**
34: * The current user.
35: *
36: * @var string
37: */
38: protected $_auth;
39:
40: /**
41: * Our log handler.
42: *
43: * @var Horde_Log_Logger
44: */
45: protected $_logger;
46:
47: /**
48: * Constructor.
49: *
50: * @param string $auth The current user.
51: */
52: public function __construct($auth)
53: {
54: $this->_auth = $auth;
55: }
56:
57: /**
58: * Set the log handler.
59: *
60: * @param Horde_Log_Logger $logger The log handler.
61: *
62: * @return NULL
63: */
64: public function setLogger(Horde_Log_Logger $logger)
65: {
66: $this->_logger = $logger;
67: }
68:
69: /**
70: * Logs an event to an item's history log.
71: *
72: * The item must be uniquely identified by $guid. Any other details about
73: * the event are passed in $attributes. Standard suggested attributes are:
74: * - who: The id of the user that performed the action (will be added
75: * automatically if not present).
76: * - ts: Timestamp of the action (this will be added automatically if it
77: * is not present).
78: *
79: * @param string $guid The unique identifier of the entry to add
80: * to.
81: * @param array $attributes The hash of name => value entries that
82: * describe this event.
83: * @param boolean $replaceAction If $attributes['action'] is already
84: * present in the item's history log, update
85: * that entry instead of creating a new one.
86: *
87: * @throws Horde_History_Exception
88: */
89: public function log($guid, array $attributes = array(),
90: $replaceAction = false)
91: {
92: if (!is_string($guid)) {
93: throw new Horde_History_Exception('The guid needs to be a string!');
94: }
95:
96: $history = $this->getHistory($guid);
97:
98: if (!isset($attributes['who'])) {
99: $attributes['who'] = $this->_auth;
100: }
101: if (!isset($attributes['ts'])) {
102: $attributes['ts'] = time();
103: }
104:
105: $this->_log($history, $attributes, $replaceAction);
106: }
107:
108: /**
109: * Logs an event to an item's history log. Any other details about the
110: * event are passed in $attributes.
111: *
112: * @param Horde_History_Log $history The history item to add to.
113: * @param array $attributes The hash of name => value
114: * entries that describe this
115: * event.
116: * @param boolean $replaceAction If $attributes['action'] is
117: * already present in the item's
118: * history log, update that entry
119: * instead of creating a new one.
120: *
121: * @throws Horde_History_Exception
122: */
123: abstract protected function _log(Horde_History_Log $history,
124: array $attributes, $replaceAction = false);
125:
126: /**
127: * Returns a Horde_History_Log corresponding to the named history entry,
128: * with the data retrieved appropriately.
129: *
130: * @param string $guid The name of the history entry to retrieve.
131: *
132: * @return Horde_History_Log A Horde_History_Log object.
133: *
134: * @throws Horde_History_Exception
135: */
136: public function getHistory($guid)
137: {
138: if (!is_string($guid)) {
139: throw new Horde_History_Exception('The guid needs to be a string!');
140: }
141: return $this->_getHistory($guid);
142: }
143:
144: /**
145: * Returns a Horde_History_Log corresponding to the named history entry,
146: * with the data retrieved appropriately.
147: *
148: * @param string $guid The name of the history entry to retrieve.
149: *
150: * @return Horde_History_Log A Horde_History_Log object.
151: */
152: abstract public function _getHistory($guid);
153:
154: /**
155: * Finds history objects by timestamp, and optionally filter on other
156: * fields as well.
157: *
158: * @param string $cmp The comparison operator (<, >, <=, >=, or =) to
159: * check the timestamps with.
160: * @param integer $ts The timestamp to compare against.
161: * @param array $filters An array of additional (ANDed) criteria.
162: * Each array value should be an array with 3
163: * entries:
164: * - field: the history field being compared (i.e.
165: * 'action').
166: * - op: the operator to compare this field with.
167: * - value: the value to check for (i.e. 'add').
168: * @param string $parent The parent history to start searching at. If
169: * non-empty, will be searched for with a LIKE
170: * '$parent:%' clause.
171: *
172: * @return array An array of history object ids, or an empty array if
173: * none matched the criteria.
174: *
175: * @throws Horde_History_Exception
176: */
177: public function getByTimestamp($cmp, $ts, array $filters = array(),
178: $parent = null)
179: {
180: if (!is_string($cmp)) {
181: throw new Horde_History_Exception('The comparison operator needs to be a string!');
182: }
183: if (!is_integer($ts)) {
184: throw new Horde_History_Exception('The timestamp needs to be an integer!');
185: }
186: return $this->_getByTimestamp($cmp, $ts, $filters, $parent);
187: }
188:
189: /**
190: * Finds history objects by timestamp, and optionally filter on other
191: * fields as well.
192: *
193: * @param string $cmp The comparison operator (<, >, <=, >=, or =) to
194: * check the timestamps with.
195: * @param integer $ts The timestamp to compare against.
196: * @param array $filters An array of additional (ANDed) criteria.
197: * Each array value should be an array with 3
198: * entries:
199: * - field: the history field being compared (i.e.
200: * 'action').
201: * - op: the operator to compare this field with.
202: * - value: the value to check for (i.e. 'add').
203: * @param string $parent The parent history to start searching at. If
204: * non-empty, will be searched for with a LIKE
205: * '$parent:%' clause.
206: *
207: * @return array An array of history object ids, or an empty array if
208: * none matched the criteria.
209: *
210: * @throws Horde_History_Exception
211: */
212: abstract public function _getByTimestamp($cmp, $ts,
213: array $filters = array(),
214: $parent = null);
215:
216: /**
217: * Gets the timestamp of the most recent change to $guid.
218: *
219: * @param string $guid The name of the history entry to retrieve.
220: * @param string $action An action: 'add', 'modify', 'delete', etc.
221: *
222: * @return integer The timestamp, or 0 if no matching entry is found.
223: *
224: * @throws Horde_History_Exception If the input parameters are not of type string.
225: */
226: public function getActionTimestamp($guid, $action)
227: {
228: if (!is_string($guid) || !is_string($action)) {
229: throw new Horde_History_Exception('$guid and $action need to be strings!');
230: }
231:
232: try {
233: $history = $this->getHistory($guid);
234: } catch (Horde_History_Exception $e) {
235: return 0;
236: }
237:
238: $last = 0;
239:
240: foreach ($history as $entry) {
241: if (($entry['action'] == $action) && ($entry['ts'] > $last)) {
242: $last = $entry['ts'];
243: }
244: }
245:
246: return (int)$last;
247: }
248:
249: /**
250: * Remove one or more history entries by parent.
251: *
252: * @param string $parent The parent name to remove.
253: *
254: * @throws Horde_History_Exception
255: */
256: public function removeByParent($parent)
257: {
258: /* Remove entries 100 at a time. */
259: $all = array_keys($this->getByTimestamp('>', 0, array(), $parent));
260:
261: while (count($d = array_splice($all, 0, 100)) > 0) {
262: $this->removebyNames($d);
263: }
264: }
265:
266: /**
267: * Removes one or more history entries by name.
268: *
269: * @param array $names The history entries to remove.
270: *
271: * @throws Horde_History_Exception
272: */
273: abstract public function removeByNames(array $names);
274: }
275: