/
Base.php
226 lines (204 loc) · 7.21 KB
/
Base.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
<?php
/**
* The hook that updates the Horde history information once data gets
* synchronized with the Kolab backend.
*
* PHP version 5
*
* @category Kolab
* @package Kolab_Storage
* @author Gunnar Wrobel <wrobel@pardus.de>
* @author Thomas Jarosch <thomas.jarosch@intra2net.com>
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @link http://pear.horde.org/index.php?package=Kolab_Storage
*/
/**
* The hook that updates the Horde history information once data gets
* synchronized with the Kolab backend.
*
* Copyright 2011-2015 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.
*
* @category Kolab
* @package Kolab_Storage
* @author Gunnar Wrobel <wrobel@pardus.de>
* @author Thomas Jarosch <thomas.jarosch@intra2net.com>
* @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
* @link http://pear.horde.org/index.php?package=Kolab_Storage
*/
class Horde_Kolab_Storage_Data_Query_History_Base
implements Horde_Kolab_Storage_Data_Query_History
{
/**
* The factory for generating additional resources.
*
* @var Horde_Kolab_Storage_Factory
*/
protected $factory;
/**
* The queriable data.
*
* @var Horde_Kolab_Storage_Data
*/
protected $data;
/**
* The history handler.
*
* @var Horde_History
*/
protected $history;
/**
* The precomputed history prefix
*
* @var string Cached history prefix string
*/
private $_prefix;
/**
* Constructor.
*
* @param Horde_Kolab_Storage_Data $data The queriable data.
* @param array $params Additional parameters.
*/
public function __construct(Horde_Kolab_Storage_Data $data,
$params)
{
$this->data = $data;
$this->factory = $params['factory'];
$this->history = $this->factory->createHistory($data->getAuth());
}
/**
* Synchronize the preferences information with the information from the
* backend.
*
* @param array $params Additional parameters:
* - changes: (array) An array of arrays keyed by backend id containing
* information about each change.
*
* @return NULL
*/
public function synchronize($params = array())
{
$prefix = $this->_constructHistoryPrefix();
// Abort history update if we can't determine the prefix.
// Otherwise we pollute the database with useless entries.
if (empty($prefix))
return;
// check if IMAP uidvalidity changed
$is_reset = !empty($params['is_reset']);
if (isset($params['changes']) && !$is_reset) {
foreach ($params['changes'][Horde_Kolab_Storage_Folder_Stamp::ADDED] as $bid => $object) {
$this->_updateLog($prefix.$object['uid'], $bid);
}
foreach ($params['changes'][Horde_Kolab_Storage_Folder_Stamp::DELETED] as $bid => $object_uid) {
// Check if the object is really gone from the folder.
// Otherwise we just deleted a duplicated object or updated the original one.
// (An update results in an ADDED + DELETED folder action)
if ($this->data->objectIdExists($object_uid) == true)
continue;
$this->history->log(
$prefix.$object_uid, array('action' => 'delete', 'bid' => $bid), true
);
}
} else {
foreach ($this->data->getObjectToBackend() as $object => $bid) {
$this->_updateLog($prefix.$object, $bid);
}
}
}
/**
* Construct prefix needed for Horde_History entries.
*
* Horde history entries are prefixed and filtered
* by application name and base64 encoded folder name.
*
* @return string Constructed prefix. Can be empty.
*/
private function _constructHistoryPrefix()
{
// Check if we already know the full prefix
if (!empty($this->_prefix))
return $this->_prefix;
$type = $this->_type2app($this->data->getType());
if (empty($type))
return '';
// Determine share name
$share_name = '';
$folder = $this->data->getPath();
// TODO: Access global Kolab_Storage object if possible
// We probably have to extend the class structure for this.
$query = $this->factory->create()->getList()
->getQuery(Horde_Kolab_Storage_List_Tools::QUERY_SHARE);
$data = $query->getParameters($folder);
if (isset($data['share_name']))
$share_name = $data['share_name'];
else
return '';
$this->_prefix = $type.':'.$share_name.':';
return $this->_prefix;
}
/**
* Map Kolab object type to horde application name.
*
* @param string $type Kolab object type
*
* @return string The horde application name. Empty string if unknown
*/
private function _type2app($type)
{
$mapping = array(
'contact' => 'turba',
'event' => 'kronolith',
'note' => 'mnemo',
'task' => 'nag',
);
if (isset($mapping[$type]))
return $mapping[$type];
return '';
}
/**
* Update the history log for an object.
*
* @param string $object The object ID.
* @param string $bid The backend ID of
* the object.
* @param bool $force Force update
*
* @return NULL
*/
private function _updateLog($object, $bid, $force=false)
{
$log = $this->history->getHistory($object);
if (count($log) == 0) {
$this->history->log(
$object, array('action' => 'add', 'bid' => $bid), true
);
} else {
$last = array('ts' => 0);
foreach ($log as $entry) {
$action = $entry['action'];
if ($entry['ts'] > $last['ts'] && ($action == 'add' || $action == 'modify' || $action == 'delete')) {
$last = $entry;
} else if ($entry['ts'] == $last['ts'] && $action == 'delete') {
// prefer 'delete' actions over other actions if the timestamp is the same.
// see the logic below.
$last = $entry;
}
}
// If the last action for this object was 'delete', we issue an 'add'.
// Objects can vanish and re-appear using the same object uid.
// (a foreign client is sending an update over a slow link)
if ($last['action'] == 'delete') {
$this->history->log(
$object, array('action' => 'add', 'bid' => $bid), true
);
}
if (!isset($last['bid']) || $last['bid'] != $bid || $force) {
$this->history->log(
$object, array('action' => 'modify', 'bid' => $bid), true
);
}
}
}
}