1: <?php
2: /**
3: * Copyright 2013-2014 Horde LLC (http://www.horde.org/)
4: *
5: * See the enclosed file COPYING for license information (GPL). If you
6: * did not receive this file, see http://www.horde.org/licenses/gpl.
7: *
8: * @category Horde
9: * @copyright 2013-2014 Horde LLC
10: * @license http://www.horde.org/licenses/gpl GPL
11: * @package IMP
12: */
13:
14: /**
15: * Track element changes in the folder tree.
16: *
17: * @author Michael Slusarz <slusarz@horde.org>
18: * @category Horde
19: * @copyright 2013-2014 Horde LLC
20: * @license http://www.horde.org/licenses/gpl GPL
21: * @package IMP
22: *
23: * @method void add(string $elt) Element added to tree.
24: * @method void change(string $elt) Element changed in tree.
25: * @method void delete(string $elt) Element deleted in tree.
26: *
27: * @property-read array $add List of added elements.
28: * @property-read array $change List of changed elements.
29: * @property-read integer $changed_elts The number of changed elements
30: * tracked.
31: * @property-read array $delete List of deleted elements.
32: * @property boolean $track Is tracking active?
33: */
34: class IMP_Ftree_Eltdiff implements Serializable
35: {
36: /* Constants for $_changes values. */
37: const ADD = 1;
38: const CHANGE = 2;
39: const DELETE = 4;
40: const EXIST = 8;
41:
42: /**
43: * Has the internal data structure changed?
44: *
45: * @var boolean
46: */
47: public $changed = false;
48:
49: /**
50: * List of diffs.
51: *
52: * @var array
53: */
54: protected $_changes = array();
55:
56: /**
57: * Is tracking active?
58: *
59: * @var boolean
60: */
61: protected $_track = false;
62:
63: /**
64: */
65: public function __call($name, $args)
66: {
67: switch ($name) {
68: case 'add':
69: case 'change':
70: case 'delete':
71: if ($this->track) {
72: $elt = reset($args);
73:
74: /* Don't track base element. */
75: if ($elt instanceof IMP_Ftree_Element) {
76: if ($elt->base_elt) {
77: return;
78: }
79: } elseif (!strlen($elt)) {
80: return;
81: }
82:
83: $elt = strval($elt);
84: $value = isset($this->_changes[$elt])
85: ? $this->_changes[$elt]
86: : null;
87:
88: switch ($name) {
89: case 'add':
90: if (is_null($value)) {
91: $value = self::ADD;
92: } elseif ($value & self::EXIST) {
93: $value = self::CHANGE | self::EXIST;
94: } else {
95: $value &= ~self::CHANGE & ~self::DELETE;
96: $value |= self::ADD;
97: }
98: break;
99:
100: case 'change':
101: if (is_null($value)) {
102: $value = self::CHANGE | self::EXIST;
103: } elseif (($value & self::EXIST) ||
104: !($value & self::ADD)) {
105: $value &= ~self::ADD & ~self::DELETE;
106: $value |= self::CHANGE;
107: }
108: break;
109:
110: case 'delete':
111: if (is_null($value)) {
112: $value = self::DELETE | self::EXIST;
113: } else {
114: $value &= ~self::ADD & ~self::CHANGE;
115: $value |= self::DELETE;
116: }
117: break;
118: }
119:
120: $this->_changes[$elt] = $value;
121: }
122: break;
123: }
124: }
125:
126: /**
127: */
128: public function __get($name)
129: {
130: switch ($name) {
131: case 'add':
132: case 'change':
133: case 'delete':
134: switch ($name) {
135: case 'add':
136: $mask = self::ADD;
137: break;
138:
139: case 'change':
140: $mask = self::CHANGE;
141: break;
142:
143: case 'delete':
144: $mask = self::DELETE;
145: break;
146: }
147:
148: $out = array();
149: foreach ($this->_changes as $key => $val) {
150: if ($val & $mask) {
151: $out[] = $key;
152: }
153: }
154: return $out;
155:
156: case 'changed_elts':
157: return count($this->_changes);
158:
159: case 'track':
160: return $this->_track;
161: }
162: }
163:
164: /**
165: */
166: public function __set($name, $value)
167: {
168: switch ($name) {
169: case 'track':
170: $value = (bool)$value;
171: if ($value != $this->_track) {
172: $this->_track = $value;
173: $this->changed = true;
174: }
175: break;
176: }
177: }
178:
179: /**
180: * Clear diff stats.
181: */
182: public function clear()
183: {
184: if (!empty($this->_changes)) {
185: $this->_changes = array();
186: $this->changed = true;
187: }
188: }
189:
190: /* Serializable methods. */
191:
192: /**
193: */
194: public function serialize()
195: {
196: return $GLOBALS['injector']->getInstance('Horde_Pack')->pack(
197: array(
198: $this->track,
199: $this->_changes
200: ),
201: array(
202: 'compression' => false,
203: 'phpob' => false
204: )
205: );
206: }
207:
208: /**
209: */
210: public function unserialize($data)
211: {
212: list(
213: $this->track,
214: $this->_changes
215: ) = $GLOBALS['injector']->getInstance('Horde_Pack')->unpack($data);
216: }
217:
218: }
219: