PageRenderTime 62ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/imp/lib/Search/Query.php

https://github.com/sgtcarneiro/horde
PHP | 348 lines | 178 code | 48 blank | 122 comment | 23 complexity | de6d004a79f9e23a5b46c14929c2d4b4 MD5 | raw file
  1. <?php
  2. /**
  3. * This class provides a data structure for a search query.
  4. *
  5. * Copyright 2010-2011 The Horde Project (http://www.horde.org/)
  6. *
  7. * See the enclosed file COPYING for license information (GPL). If you
  8. * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
  9. *
  10. * @author Michael Slusarz <slusarz@horde.org>
  11. * @category Horde
  12. * @license http://www.fsf.org/copyleft/gpl.html GPL
  13. * @package IMP
  14. *
  15. * @property boolean $all Does this query search all mailboxes?
  16. * @property boolean $canEdit Can this query be edited?
  17. * @property string $id The query ID.
  18. * @property string $label The query label.
  19. * @property array $mboxes The list of mailboxes to query. This list
  20. * automatically expands subfolder searches.
  21. * @property array $mbox_list The list of individual mailboxes to query (no
  22. * subfolder mailboxes).
  23. * @property IMP_Mailbox $mbox_ob The IMP_Mailbox object for this query.
  24. * @property string $mid The query ID with the search mailbox prefix.
  25. * @property array $query The list of IMAP queries that comprise this search.
  26. * Keys are mailbox names, values are
  27. * Horde_Imap_Client_Search_Query objects.
  28. * @property string $querytext The textual representation of the query.
  29. * @property array $subfolder_list The list of mailboxes to do subfolder
  30. * queries for. The subfolders are not
  31. * expanded.
  32. */
  33. class IMP_Search_Query implements Serializable
  34. {
  35. /* Serialized version. */
  36. const VERSION = 1;
  37. /* Prefix indicating subfolder search. */
  38. const SUBFOLDER = "sub\0";
  39. /* Mailbox value indicating a search all mailboxes search. */
  40. const ALLSEARCH = "all\0";
  41. /**
  42. * Is this query enabled?
  43. *
  44. * @var boolean
  45. */
  46. public $enabled = true;
  47. /**
  48. * Cache results.
  49. *
  50. * @var array
  51. */
  52. protected $_cache = array();
  53. /**
  54. * Can this query be edited?
  55. *
  56. * @var boolean
  57. */
  58. protected $_canEdit = true;
  59. /**
  60. * The search criteria (IMP_Search_Element objects).
  61. *
  62. * @var array
  63. */
  64. protected $_criteria = array();
  65. /**
  66. * The search ID.
  67. *
  68. * @var string
  69. */
  70. protected $_id;
  71. /**
  72. * The virtual folder label.
  73. *
  74. * @var string
  75. */
  76. protected $_label;
  77. /**
  78. * The mailbox list.
  79. *
  80. * @var array
  81. */
  82. protected $_mboxes = array();
  83. /**
  84. * List of serialize entries not to save.
  85. *
  86. * @var array
  87. */
  88. protected $_nosave = array();
  89. /**
  90. * Constructor.
  91. *
  92. * @var array $opts Options:
  93. * - add: (array) A list of criteria to add (Horde_Search_Element
  94. * objects).
  95. * DEFAULT: No criteria explicitly added.
  96. * - all: (boolean) Search all mailboxes? If set, ignores 'mboxes' and
  97. * 'subfolders' options.
  98. * DEFAULT: false
  99. * - disable: (boolean) Disable this query?
  100. * DEFAULT: false
  101. * - id: (string) Use this ID.
  102. * DEFAULT: ID automatically generated.
  103. * - label: (string) The label for this query.
  104. * DEFAULT: Search Results
  105. * - mboxes: (array) The list of mailboxes to search.
  106. * DEFAULT: None
  107. * - subfolders: (array) The list of mailboxes to do subfolder searches
  108. * for.
  109. * DEFAULT: None
  110. */
  111. public function __construct(array $opts = array())
  112. {
  113. $this->enabled = empty($opts['disable']);
  114. if (isset($opts['add'])) {
  115. foreach ($opts['add'] as $val) {
  116. $this->add($val);
  117. }
  118. }
  119. $this->_id = isset($opts['id'])
  120. ? $opts['id']
  121. : strval(new Horde_Support_Randomid());
  122. $this->_label = isset($opts['label'])
  123. ? $opts['label']
  124. : _("Search Results");
  125. if (!empty($opts['all'])) {
  126. $this->_mboxes = array(self::ALLSEARCH);
  127. } else {
  128. if (isset($opts['mboxes'])) {
  129. $this->_mboxes = $opts['mboxes'];
  130. }
  131. if (isset($opts['subfolders'])) {
  132. foreach ($opts['subfolders'] as $val) {
  133. $this->_mboxes[] = self::SUBFOLDER . $val;
  134. }
  135. }
  136. natsort($this->_mboxes);
  137. }
  138. }
  139. /**
  140. */
  141. public function __get($name)
  142. {
  143. switch ($name) {
  144. case 'all':
  145. return in_array(self::ALLSEARCH, $this->_mboxes);
  146. case 'canEdit':
  147. return $this->_canEdit;
  148. case 'criteria':
  149. $out = array();
  150. foreach ($this->_criteria as $elt) {
  151. $out[] = array(
  152. 'criteria' => $elt->getCriteria(),
  153. 'element' => get_class($elt)
  154. );
  155. }
  156. return $out;
  157. case 'id':
  158. return $this->_id;
  159. case 'label':
  160. return $this->_label;
  161. case 'mboxes':
  162. if (!isset($this->_cache['mboxes'])) {
  163. $out = $this->mbox_list;
  164. if (!$this->all &&
  165. ($s_list = $this->subfolder_list)) {
  166. foreach ($s_list as $val) {
  167. $out = array_merge($out, $val->subfolders);
  168. }
  169. }
  170. // TODO: array_unique() for objects (requires 5.2.9)
  171. $this->_cache['mboxes'] = $out;
  172. }
  173. return $this->_cache['mboxes'];
  174. case 'mbox_list':
  175. case 'subfolder_list':
  176. if (!isset($this->_cache['mbox_list'])) {
  177. $mbox = $subfolder = array();
  178. if ($this->all) {
  179. $imaptree = $GLOBALS['injector']->getInstance('IMP_Imap_Tree');
  180. $imaptree->setIteratorFilter(IMP_Imap_Tree::FLIST_NOCONTAINER);
  181. $mbox = iterator_to_array($imaptree);
  182. } else {
  183. foreach ($this->_mboxes as $val) {
  184. if (strpos($val, self::SUBFOLDER) === 0) {
  185. $subfolder[] = IMP_Mailbox::get(substr($val, strlen(self::SUBFOLDER)));
  186. } else {
  187. $mbox[] = IMP_Mailbox::get($val);
  188. }
  189. }
  190. }
  191. $this->_cache['mbox_list'] = $mbox;
  192. $this->_cache['subfolder_list'] = $subfolder;
  193. }
  194. return $this->_cache[$name];
  195. case 'mbox_ob':
  196. return IMP_Mailbox::get($this->mid);
  197. case 'mid':
  198. return IMP_Search::MBOX_PREFIX . $this->_id;
  199. case 'query':
  200. $qout = array();
  201. foreach ($this->mboxes as $mbox) {
  202. $query = new Horde_Imap_Client_Search_Query();
  203. foreach ($this->_criteria as $elt) {
  204. $query = $elt->createQuery($mbox, $query);
  205. }
  206. $qout[strval($mbox)] = $query;
  207. }
  208. return $qout;
  209. case 'querytext':
  210. $text = array(_("Search"));
  211. foreach ($this->_criteria as $elt) {
  212. if ($elt instanceof IMP_Search_Element_Or) {
  213. array_pop($text);
  214. $text[] = $elt->queryText();
  215. } else {
  216. $text[] = $elt->queryText();
  217. $text[] = _("and");
  218. }
  219. }
  220. array_pop($text);
  221. $mbox_display = array();
  222. if ($this->all) {
  223. $mbox_display[] = _("All Mailboxes");
  224. } else {
  225. foreach ($this->mboxes as $val) {
  226. $mbox_display[] = $val->display;
  227. }
  228. }
  229. return implode(' ', $text) . ' ' . _("in") . ' [' . implode(', ', $mbox_display) . ']';
  230. }
  231. }
  232. /**
  233. * String representation of this object: the mailbox ID.
  234. *
  235. * @return string Mailbox ID.
  236. */
  237. public function __toString()
  238. {
  239. return $this->mid;
  240. }
  241. /**
  242. * Add a search query element.
  243. *
  244. * @param IMP_Search_Element $elt The search element to add.
  245. */
  246. public function add(IMP_Search_Element $elt)
  247. {
  248. $this->_criteria[] = $elt;
  249. }
  250. /* Serializable methods. */
  251. /**
  252. * Serialization.
  253. *
  254. * @return string Serialized data.
  255. */
  256. public function serialize()
  257. {
  258. $data = array_filter(array(
  259. 'c' => $this->_criteria,
  260. 'e' => intval($this->enabled),
  261. 'i' => $this->_id,
  262. 'l' => $this->_label,
  263. 'm' => $this->_mboxes,
  264. 'v' => self::VERSION
  265. ));
  266. foreach ($this->_nosave as $val) {
  267. unset($data[$val]);
  268. }
  269. return serialize($data);
  270. }
  271. /**
  272. * Unserialization.
  273. *
  274. * @param string $data Serialized data.
  275. *
  276. * @throws Exception
  277. */
  278. public function unserialize($data)
  279. {
  280. $data = unserialize($data);
  281. if (!is_array($data) ||
  282. !isset($data['v']) ||
  283. ($data['v'] != self::VERSION)) {
  284. throw new Exception('Cache version change');
  285. }
  286. if (isset($data['c'])) {
  287. $this->_criteria = $data['c'];
  288. }
  289. $this->enabled = !empty($data['e']);
  290. if (isset($data['i'])) {
  291. $this->_id = $data['i'];
  292. }
  293. if (isset($data['l'])) {
  294. $this->_label = $data['l'];
  295. }
  296. if (isset($data['m'])) {
  297. $this->_mboxes = $data['m'];
  298. }
  299. }
  300. }