1: <?php
2: /**
3: * An object that provides a way to identify a list of IMAP indices.
4: *
5: * Copyright 2011-2012 Horde LLC (http://www.horde.org/)
6: *
7: * See the enclosed file COPYING for license information (LGPL). If you
8: * did not receive this file, see http://www.horde.org/licenses/lgpl21.
9: *
10: * @author Michael Slusarz <slusarz@horde.org>
11: * @category Horde
12: * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1
13: * @package Imap_Client
14: *
15: * @property boolean $all Does this represent an ALL message set?
16: * @property array $ids The list of IDs.
17: * @property boolean $search_res Does this represent a search result?
18: * @property boolean $sequence Are these sequence IDs? If false, these are
19: * UIDs.
20: * @property boolean $tostring Return the non-sorted string representation.
21: * @property boolean $tostring_sort Return the sorted string representation.
22: */
23: class Horde_Imap_Client_Ids implements Countable, Iterator, Serializable
24: {
25: /* Constants. */
26: const ALL = "\01";
27: const SEARCH_RES = "\02";
28:
29: /**
30: * List of IDs.
31: *
32: * @var mixed
33: */
34: protected $_ids = array();
35:
36: /**
37: * Are IDs message sequence numbers?
38: *
39: * @var boolean
40: */
41: protected $_sequence = false;
42:
43: /**
44: * The utility class to use to parse a sequence string.
45: *
46: * @var string
47: */
48: protected $_utilsClass = 'Horde_Imap_Client_Utils';
49:
50: /**
51: * Constructor.
52: *
53: * @param mixed $ids See self::add().
54: * @param boolean $sequence Are $ids message sequence numbers?
55: */
56: public function __construct($ids = null, $sequence = false)
57: {
58: $this->add($ids);
59: $this->_sequence = $sequence;
60: }
61:
62: /**
63: */
64: public function __get($name)
65: {
66: switch ($name) {
67: case 'all':
68: return ($this->_ids === self::ALL);
69:
70: case 'ids':
71: return is_array($this->_ids)
72: ? $this->_ids
73: : array();
74:
75: case 'search_res':
76: return ($this->_ids === self::SEARCH_RES);
77:
78: case 'sequence':
79: return (bool)$this->_sequence;
80:
81: case 'tostring':
82: case 'tostring_sort':
83: $utils = new $this->_utilsClass();
84: return strval($utils->toSequenceString($this->_ids, array(
85: 'nosort' => ($name == 'tostring')
86: )));
87: }
88: }
89:
90: /**
91: */
92: public function __toString()
93: {
94: return $this->tostring;
95: }
96:
97: /**
98: * Add IDs to the current object.
99: *
100: * @param mixed $ids Either self::ALL, self::SEARCH_RES,
101: * Horde_Imap_Client_Ids object, array, or string.
102: */
103: public function add($ids)
104: {
105: if (!is_null($ids)) {
106: $add = array();
107:
108: if (($ids === self::ALL) || ($ids === self::SEARCH_RES)) {
109: $this->_ids = $ids;
110: return;
111: }
112:
113: if ($ids instanceof Horde_Imap_Client_Ids) {
114: $add = $ids->ids;
115: } elseif (is_array($ids)) {
116: $add = $ids;
117: } elseif (is_string($ids) || is_integer($ids)) {
118: if (is_numeric($ids)) {
119: $add = array($ids);
120: } else {
121: $utils = new $this->_utilsClass();
122: $add = $utils->fromSequenceString($ids);
123: }
124: }
125:
126: $this->_ids = is_array($this->_ids)
127: ? array_keys(array_flip(array_merge($this->_ids, $add)))
128: : $add;
129: }
130: }
131:
132: /**
133: * Is this object empty (i.e. does not contain IDs)?
134: *
135: * @return boolean True if object is empty.
136: */
137: public function isEmpty()
138: {
139: return (is_array($this->_ids) && !count($this->_ids));
140: }
141:
142: /**
143: */
144: public function reverse()
145: {
146: if (is_array($this->_ids)) {
147: $this->_ids = array_reverse($this->_ids);
148: }
149: }
150:
151: /* Countable methods. */
152:
153: /**
154: */
155: public function count()
156: {
157: return is_array($this->_ids)
158: ? count($this->_ids)
159: : 0;
160: }
161:
162: /* Iterator methods. */
163:
164: /**
165: */
166: public function current()
167: {
168: return is_array($this->_ids)
169: ? current($this->_ids)
170: : null;
171: }
172:
173: /**
174: */
175: public function key()
176: {
177: return is_array($this->_ids)
178: ? key($this->_ids)
179: : null;
180: }
181:
182: /**
183: */
184: public function next()
185: {
186: if (is_array($this->_ids)) {
187: next($this->_ids);
188: }
189: }
190:
191: /**
192: */
193: public function rewind()
194: {
195: if (is_array($this->_ids)) {
196: reset($this->_ids);
197: }
198: }
199:
200: /**
201: */
202: public function valid()
203: {
204: return !is_null($this->key());
205: }
206:
207: /* Serializable methods. */
208:
209: /**
210: */
211: public function serialize()
212: {
213: $save = array();
214:
215: if ($this->_sequence) {
216: $save['s'] = 1;
217: }
218:
219: switch ($this->_ids) {
220: case self::ALL:
221: $save['a'] = true;
222: break;
223:
224: case self::SEARCH_RES:
225: $save['sr'] = true;
226: break;
227:
228: default:
229: $save['i'] = strval($this);
230: break;
231: }
232:
233: return serialize($save);
234: }
235:
236: /**
237: */
238: public function unserialize($data)
239: {
240: $save = @unserialize($data);
241:
242: $this->_sequence = !empty($save['s']);
243:
244: if (isset($save['a'])) {
245: $this->_ids = self::ALL;
246: } elseif (isset($save['sr'])) {
247: $this->_ids = self::SEARCH_RES;
248: } elseif (isset($save['i'])) {
249: $this->add($save['i']);
250: }
251: }
252:
253: }
254: