1: <?php
2:
3: /**
4: * Contacts modules
5: * @package modules
6: * @subpackage contacts
7: */
8:
9: if (!defined('DEBUG_MODE')) { die(); }
10:
11: /**
12: * @subpackage contacts/lib
13: */
14: class Hm_Contact_Store {
15:
16: use Hm_Repository {
17: Hm_Repository::save as repo_save;
18: Hm_Repository::get as repo_get;
19: }
20:
21: private $data = array();
22: private $sort_fld = false;
23:
24: public function init($user_config, $session) {
25: self::initRepo('contacts', $user_config, $session, $this->data, function($initial) {
26: foreach ($initial as $contact) {
27: $this->add_contact($contact, false);
28: }
29: });
30: }
31:
32: public static function save() {
33: $local_contacts = array_map(function($c) {
34: $c->update('type', 'local');
35: return $c->export();
36: }, array_filter(self::$entities, function($c) {
37: return ! $c->value('external');
38: }));
39: self::$user_config->set(self::$name, $local_contacts);
40: self::$session->set('user_data', self::$user_config->dump());
41: }
42:
43: public function __construct() {
44: }
45:
46: public function add_contact($data, $save = true) {
47: $contact = new Hm_Contact($data);
48: if ($contact->value('external')) {
49: $save = false;
50: }
51: self::add($contact, $save);
52: return true;
53: }
54:
55: public function get($id, $default=false, $email_address=""){
56: $contact = self::repo_get($id);
57: if ($contact) {
58: return $contact;
59: }
60:
61: if(!empty($email_address)){
62: $res = false;
63: foreach (self::getAll() as $id => $contact) {
64: if ($contact->value('email_address') == $email_address) {
65: $res = $contact;
66: break;
67: }
68: }
69:
70: return $res;
71: }
72:
73: return $default;
74: }
75:
76: public function search($flds) {
77: $res = array();
78: $found = array();
79: foreach ($flds as $fld => $term) {
80: foreach (self::getAll() as $id => $contact) {
81: if (array_key_exists($contact->value('email_address'), $found)) {
82: continue;
83: }
84: if ($this->search_contact($contact, $fld, $term)) {
85: $res[$id] = [$id, $contact];
86: $found[$contact->value('email_address')] = 1;
87: }
88: }
89: }
90: return $res;
91: }
92:
93: protected function search_contact($contact, $fld, $term) {
94: if (mb_stristr($contact->value($fld, ''), $term)) {
95: return true;
96: }
97: return false;
98: }
99:
100: public function update_contact_fld($contact, $name, $value) {
101: return $contact->update($name, $value);
102: }
103:
104: public function update_contact($id, $flds) {
105: if (!$contact = $this->get($id)) {
106: return false;
107: }
108: $failures = 0;
109: foreach ($flds as $name => $value) {
110: $failures += (int) !$this->update_contact_fld($contact, $name, $value);
111: }
112: if ($failures == 0) {
113: $this->edit($id, $contact);
114: }
115: return $failures > 0 ? false : true;
116: }
117:
118: public function delete($id) {
119: return self::del($id);
120: }
121:
122:
123: public function dump() {
124: return $this->data;
125: }
126:
127: public function export($source = 'local') {
128: return array_map(function($contact) { return $contact->export(); },
129: array_filter($this->data, function($contact) use ($source) { return $contact->value('source') == $source; })
130: );
131: }
132:
133: public function import($data) {
134: foreach ($data as $contact) {
135: $contact['external'] = true;
136: $contact = new Hm_Contact($contact);
137: self::add($contact, false);
138: }
139: }
140:
141: public function reset() {
142: $this->data = array();
143: }
144:
145: public function page($page, $size, $data = null) {
146: if ($page < 1) {
147: return array();
148: }
149: if ($data === null) {
150: $data = $this->data;
151: }
152: return array_slice($data, (($page - 1)*$size), $size, true);
153: }
154:
155: public function group_by($column = 'group') {
156: if (!is_string($column) && !is_int($column) && !is_float($column)) {
157: trigger_error('group_by(): The key should be a string, an integer, or a float', E_USER_ERROR);
158: return null;
159: }
160:
161: $_key = $column;
162: $grouped = [];
163: $defaultGroup = 'Collected Recipients';
164:
165: foreach ($this->data as $value) {
166: $columnValue = null;
167:
168: if (is_array($value) && isset($value[$_key])) {
169: $columnValue = $value[$_key];
170: }
171: elseif (is_object($value) && method_exists($value, 'value') && $value->value($_key)) {
172: $columnValue = $value->value($_key);
173: }
174:
175: if ($columnValue === null) {
176: $columnValue = $defaultGroup;
177: }
178:
179: $grouped[$columnValue][] = $value;
180: }
181:
182: if (func_num_args() > 1) {
183: $args = func_get_args();
184: foreach ($grouped as $key => $values) {
185: $params = array_merge([ $values ], array_slice($args, 1));
186: $grouped[$key] = call_user_func_array([ $this, 'group_by' ], $params);
187: }
188: }
189:
190: return $grouped;
191: }
192:
193:
194:
195: public function paginate_grouped($column, $page, $size) {
196: $grouped = $this->group_by($column);
197: $paginated = [];
198: foreach ($grouped as $key => $group) {
199: $paginated[$key] = $this->page($page, $size, $group);
200: }
201: return $paginated;
202: }
203:
204: public function sort($fld) {
205: $this->sort_fld = $fld;
206: uasort($this->data, array($this, 'sort_callback'));
207: }
208:
209: public function sort_callback($a, $b) {
210: return strcmp($a->value($this->sort_fld), $b->value($this->sort_fld));
211: }
212: }
213:
214: /**
215: * @subpackage contacts/lib
216: */
217: class Hm_Contact {
218:
219: private $data = array();
220:
221: function __construct($data) {
222: $this->build($data);
223: }
224:
225: function build($data) {
226: foreach ($data as $name => $value) {
227: $this->data[$name] = $value;
228: }
229: }
230:
231: function update($fld, $val) {
232: $this->data[$fld] = $val;
233: return true;
234: }
235:
236: function value($fld, $default=false) {
237: if (array_key_exists($fld, $this->data)) {
238: return $this->data[$fld];
239: }
240: return $default;
241: }
242:
243: function export() {
244: return $this->data;
245: }
246: }
247:
248: /**
249: * @subpackage contacts/lib
250: */
251: class Hm_Address_Field {
252:
253: public static function parse($string) {
254: $marker = true;
255: $string = str_replace(array('<', '>'), array(' <', '> '), $string);
256: $string = preg_replace("/\s{2,}/", ' ', $string);
257: $results = array();
258:
259: while ($marker !== false) {
260: list($marker, $token, $string) = self::get_token($string);
261: if (is_email_address($token)) {
262: list($name, $marker) = self::find_name_field($string);
263: if ($marker > -1) {
264: $string = mb_substr($string, 0, $marker);
265: }
266: else {
267: $marker = false;
268: }
269: $results[] = array('email' => $token, 'name' => $name);
270: }
271: }
272: return $results;
273: }
274:
275: private static function get_token($string) {
276: $marker = mb_strrpos($string, ' ');
277: $token = trim(ltrim(mb_substr($string, $marker)), '<>');
278: $string = mb_substr($string, 0, $marker);
279: return array($marker, $token, $string);
280: }
281:
282: private static function is_quote($string, $i, $quote) {
283: if (in_array($string[$i], array('"', "'"), true)) {
284: if (!self::embeded_quote($string, $i)) {
285: $quote = $quote ? false : true;
286: }
287: }
288: return $quote;
289: }
290:
291: private static function find_name_field($string) {
292: $quote = false;
293: $result = '';
294: for ($i = mb_strlen($string) - 1;$i>-1; $i--) {
295: $quote = self::is_quote($string, $i, $quote);
296: if (self::delimiter_found($string, $i, $quote)) {
297: break;
298: }
299: $result .= $string[$i];
300: }
301: return array(strrev(trim(trim($result),'"\'')), $i);
302: }
303:
304: private static function embeded_quote($string, $i) {
305: return $i > 0 && $string[$i -1] == '\\';
306: }
307:
308: private static function delimiter_found($string, $i, $quote) {
309: return !$quote && in_array($string[$i], array(',', ';'), true);
310: }
311: }
312: