Overview

Packages

  • IMP
  • None

Classes

  • IMP
  • IMP_Ajax_Application
  • IMP_Ajax_Imple_ContactAutoCompleter
  • IMP_Ajax_Imple_PassphraseDialog
  • IMP_Ajax_Queue
  • IMP_Api
  • IMP_Auth
  • IMP_Block_Newmail
  • IMP_Block_Summary
  • IMP_Compose
  • IMP_Compose_Exception
  • IMP_Compose_Stationery
  • IMP_Contents
  • IMP_Crypt_Pgp
  • IMP_Crypt_Smime
  • IMP_Dimp
  • IMP_Exception
  • IMP_Factory_AuthImap
  • IMP_Factory_Compose
  • IMP_Factory_Contents
  • IMP_Factory_Flags
  • IMP_Factory_Identity
  • IMP_Factory_Imap
  • IMP_Factory_Imaptree
  • IMP_Factory_Mail
  • IMP_Factory_Mailbox
  • IMP_Factory_MailboxList
  • IMP_Factory_MimeViewer
  • IMP_Factory_Pgp
  • IMP_Factory_Quota
  • IMP_Factory_Search
  • IMP_Factory_Sentmail
  • IMP_Factory_Smime
  • IMP_Filter
  • IMP_Flag_Base
  • IMP_Flag_Imap
  • IMP_Flag_Imap_Answered
  • IMP_Flag_Imap_Deleted
  • IMP_Flag_Imap_Draft
  • IMP_Flag_Imap_Flagged
  • IMP_Flag_Imap_Forwarded
  • IMP_Flag_Imap_Junk
  • IMP_Flag_Imap_NotJunk
  • IMP_Flag_Imap_Seen
  • IMP_Flag_System_Attachment
  • IMP_Flag_System_Encrypted
  • IMP_Flag_System_HighPriority
  • IMP_Flag_System_List
  • IMP_Flag_System_LowPriority
  • IMP_Flag_System_Match_Address
  • IMP_Flag_System_Match_Flag
  • IMP_Flag_System_Match_Header
  • IMP_Flag_System_Personal
  • IMP_Flag_System_Signed
  • IMP_Flag_System_Unseen
  • IMP_Flag_User
  • IMP_Flags
  • IMP_Imap
  • IMP_Imap_Acl
  • IMP_Imap_Exception
  • IMP_Imap_PermanentFlags
  • IMP_Imap_Thread
  • IMP_Imap_Tree
  • IMP_Indices
  • IMP_Indices_Form
  • IMP_LoginTasks_SystemTask_GarbageCollection
  • IMP_LoginTasks_SystemTask_Upgrade
  • IMP_LoginTasks_SystemTask_UpgradeAuth
  • IMP_LoginTasks_Task_Autocreate
  • IMP_LoginTasks_Task_DeleteAttachmentsMonthly
  • IMP_LoginTasks_Task_DeleteSentmailMonthly
  • IMP_LoginTasks_Task_FilterOnLogin
  • IMP_LoginTasks_Task_PurgeSentmail
  • IMP_LoginTasks_Task_PurgeSpam
  • IMP_LoginTasks_Task_PurgeTrash
  • IMP_LoginTasks_Task_RecoverDraft
  • IMP_LoginTasks_Task_RenameSentmailMonthly
  • IMP_Mailbox
  • IMP_Mailbox_List
  • IMP_Mailbox_List_Track
  • IMP_Maillog
  • IMP_Menu_Dimp
  • IMP_Message
  • IMP_Mime_Status
  • IMP_Mime_Viewer_Alternative
  • IMP_Mime_Viewer_Appledouble
  • IMP_Mime_Viewer_Audio
  • IMP_Mime_Viewer_Enriched
  • IMP_Mime_Viewer_Externalbody
  • IMP_Mime_Viewer_Html
  • IMP_Mime_Viewer_Images
  • IMP_Mime_Viewer_Itip
  • IMP_Mime_Viewer_Mdn
  • IMP_Mime_Viewer_Partial
  • IMP_Mime_Viewer_Pdf
  • IMP_Mime_Viewer_Pgp
  • IMP_Mime_Viewer_Plain
  • IMP_Mime_Viewer_Related
  • IMP_Mime_Viewer_Rfc822
  • IMP_Mime_Viewer_Smil
  • IMP_Mime_Viewer_Smime
  • IMP_Mime_Viewer_Status
  • IMP_Mime_Viewer_Vcard
  • IMP_Mime_Viewer_Video
  • IMP_Mime_Viewer_Zip
  • IMP_Notification_Event_Status
  • IMP_Notification_Handler_Decorator_ImapAlerts
  • IMP_Notification_Handler_Decorator_NewmailNotify
  • IMP_Notification_Listener_AjaxStatus
  • Imp_Prefs_Identity
  • IMP_Prefs_Ui
  • IMP_Quota
  • IMP_Quota_Base
  • IMP_Quota_Command
  • IMP_Quota_Hook
  • IMP_Quota_Imap
  • IMP_Quota_Maildir
  • IMP_Quota_Mdaemon
  • IMP_Quota_Mercury32
  • IMP_Quota_Null
  • IMP_Quota_Sql
  • IMP_Search
  • IMP_Search_Element
  • IMP_Search_Element_Attachment
  • IMP_Search_Element_Autogenerated
  • IMP_Search_Element_Bulk
  • IMP_Search_Element_Contacts
  • IMP_Search_Element_Date
  • IMP_Search_Element_Flag
  • IMP_Search_Element_Header
  • IMP_Search_Element_Mailinglist
  • IMP_Search_Element_Or
  • IMP_Search_Element_Personal
  • IMP_Search_Element_Recipient
  • IMP_Search_Element_Size
  • IMP_Search_Element_Text
  • IMP_Search_Element_Within
  • IMP_Search_Filter
  • IMP_Search_Filter_Attachment
  • IMP_Search_Filter_Autogenerated
  • IMP_Search_Filter_Builtin
  • IMP_Search_Filter_Bulk
  • IMP_Search_Filter_Contacts
  • IMP_Search_Filter_Mailinglist
  • IMP_Search_Filter_Personal
  • IMP_Search_Query
  • IMP_Search_Vfolder
  • IMP_Search_Vfolder_Builtin
  • IMP_Search_Vfolder_Vinbox
  • IMP_Search_Vfolder_Vtrash
  • IMP_Sentmail
  • IMP_Sentmail_Base
  • IMP_Sentmail_Null
  • IMP_Sentmail_Sql
  • IMP_Spam
  • IMP_Test
  • IMP_Tree_Flist
  • IMP_Tree_Jquerymobile
  • IMP_Tree_Simplehtml
  • IMP_Ui_Compose
  • IMP_Ui_Editor
  • IMP_Ui_Folder
  • IMP_Ui_Headers
  • IMP_Ui_Imageview
  • IMP_Ui_Mailbox
  • IMP_Ui_Message
  • IMP_Ui_Mimp
  • IMP_Ui_Search
  • IMP_Views_Compose
  • IMP_Views_ListMessages
  • IMP_Views_ShowMessage
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The IMP_Search:: class contains all code related to mailbox searching
  4:  * in IMP.
  5:  *
  6:  * Copyright 2002-2012 Horde LLC (http://www.horde.org/)
  7:  *
  8:  * See the enclosed file COPYING for license information (GPL). If you
  9:  * did not receive this file, see http://www.horde.org/licenses/gpl.
 10:  *
 11:  * @author   Michael Slusarz <slusarz@horde.org>
 12:  * @category Horde
 13:  * @license  http://www.horde.org/licenses/gpl GPL
 14:  * @package  IMP
 15:  */
 16: class IMP_Search implements ArrayAccess, Iterator, Serializable
 17: {
 18:     /* The mailbox search prefix. */
 19:     const MBOX_PREFIX = "impsearch\0";
 20: 
 21:     /* The special search mailbox names. */
 22:     const BASIC_SEARCH = 'impbsearch';
 23:     const DIMP_FILTERSEARCH = 'dimpfsearch';
 24:     const DIMP_QUICKSEARCH = 'dimpqsearch';
 25: 
 26:     /* Bitmask filters for iterator. */
 27:     const LIST_FILTER = 1;
 28:     const LIST_QUERY = 2;
 29:     const LIST_VFOLDER = 4;
 30:     const LIST_DISABLED = 8;
 31: 
 32:     /* Query creation types. */
 33:     const CREATE_FILTER = 1;
 34:     const CREATE_QUERY = 2;
 35:     const CREATE_VFOLDER = 3;
 36: 
 37:     /**
 38:      * Has the object data changed?
 39:      *
 40:      * @var boolean
 41:      */
 42:     public $changed = false;
 43: 
 44:     /**
 45:      * Iterator filter mask.
 46:      *
 47:      * @var integer
 48:      */
 49:     protected $_filter = 0;
 50: 
 51:     /**
 52:      * Search queries.
 53:      *
 54:      * Each subarray contains:
 55:      *   Keys: mailbox IDs.
 56:      *   Values: IMP_Search_Query objects.
 57:      *
 58:      * @var array
 59:      */
 60:     protected $_search = array(
 61:         'filters' => array(),
 62:         'query' => array(),
 63:         'vfolders' => array()
 64:     );
 65: 
 66:     /**
 67:      * Constructor.
 68:      */
 69:     public function __construct()
 70:     {
 71:         $this->init();
 72:     }
 73: 
 74:     /**
 75:      * Initialize session search data.
 76:      */
 77:     public function init()
 78:     {
 79:         $this->_getFilters();
 80:         $this->_getVFolders();
 81:     }
 82: 
 83:     /**
 84:      * Run a search.
 85:      *
 86:      * @param object $ob  An optional search query to add (via 'AND') to the
 87:      *                    active search (Horde_Imap_Client_Search_Query).
 88:      * @param string $id  The search query id.
 89:      *
 90:      * @return IMP_Indices  An indices object.
 91:      * @throws IMP_Imap_Exception
 92:      */
 93:     public function runSearch($ob, $id)
 94:     {
 95:         $id = $this->_strip($id);
 96:         $mbox = '';
 97:         $sorted = new IMP_Indices();
 98: 
 99:         if (!isset($this[$id]) || !($query_list = $this[$id]->query)) {
100:             return $sorted;
101:         }
102: 
103:         /* How do we want to sort results? */
104:         $sortpref = IMP_Mailbox::get($this[$id])->getSort(true);
105:         if ($sortpref['by'] == Horde_Imap_Client::SORT_THREAD) {
106:             $sortpref['by'] = $GLOBALS['prefs']->getValue('sortdate');
107:         }
108: 
109:         $imp_imap = $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create();
110: 
111:         foreach ($query_list as $mbox => $query) {
112:             if (!empty($ob)) {
113:                 $query->andSearch(array($ob));
114:             }
115:             $results = $imp_imap->search($mbox, $query, array(
116:                 'sort' => array($sortpref['by'])
117:             ));
118:             if ($sortpref['dir']) {
119:                 $results['match']->reverse();
120:             }
121:             $sorted->add($mbox, $results['match']);
122:         }
123: 
124:         return $sorted;
125:     }
126: 
127:     /**
128:      * Creates the IMAP search query in the IMP session.
129:      *
130:      * @param array $criteria  The search criteria array.
131:      * @param array $opts      Additional options:
132:      *   - id: (string) Use as the mailbox ID.
133:      *   - label: (string) The label to use for the search results.
134:      *   - mboxes: (array) The list of mailboxes to directly search. If this
135:      *             contains the IMP_Search_Query::ALLSEARCH constant, all
136:      *             mailboxes will be searched.
137:      *   - subfolders: (array) The list of mailboxes to do subfolder searches
138:      *                 on.
139:      *   - type: (integer) Query type.
140:      *
141:      * @return IMP_Search_Query  Returns the query object.
142:      * @throws InvalidArgumentException
143:      */
144:     public function createQuery($criteria, array $opts = array())
145:     {
146:         $opts = array_merge(array(
147:             'id' => null,
148:             'label' => null,
149:             'mboxes' => array(),
150:             'subfolders' => array(),
151:             'type' => self::CREATE_QUERY
152:         ), $opts);
153: 
154:         /* Make sure mailbox names are not IMP_Mailbox objects. */
155:         $opts['mboxes'] = array_map('strval', $opts['mboxes']);
156:         $opts['subfolders'] = array_map('strval', $opts['subfolders']);
157: 
158:         switch ($opts['type']) {
159:         case self::CREATE_FILTER:
160:             $cname = 'IMP_Search_Filter';
161:             break;
162: 
163:         case self::CREATE_QUERY:
164:             $cname = 'IMP_Search_Query';
165:             if (empty($opts['mboxes']) && empty($opts['subfolders'])) {
166:                 throw new InvalidArgumentException('Search query requires at least one mailbox.');
167:             }
168:             break;
169: 
170:         case self::CREATE_VFOLDER:
171:             $cname = 'IMP_Search_Vfolder';
172:             if (empty($opts['mboxes']) && empty($opts['subfolders'])) {
173:                 throw new InvalidArgumentException('Search query requires at least one mailbox.');
174:             }
175:             break;
176:         }
177: 
178:         $ob = new $cname(array_filter(array(
179:             'add' => $criteria,
180:             'all' => in_array(IMP_Search_Query::ALLSEARCH, $opts['mboxes']),
181:             'id' => $this->_strip($opts['id']),
182:             'label' => $opts['label'],
183:             'mboxes' => $opts['mboxes'],
184:             'subfolders' => $opts['subfolders']
185:         )));
186: 
187:         switch ($opts['type']) {
188:         case self::CREATE_FILTER:
189:             /* This will overwrite previous value, if it exists. */
190:             $this->_search['filters'][$ob->id] = $ob;
191:             $this->setFilters($this->_search['filters']);
192:             break;
193: 
194:         case self::CREATE_QUERY:
195:             $this->_search['query'][$ob->id] = $ob;
196:             break;
197: 
198:         case self::CREATE_VFOLDER:
199:             /* This will overwrite previous value, if it exists. */
200:             $this->_search['vfolders'][$ob->id] = $ob;
201:             $this->setVFolders($this->_search['vfolders']);
202:             break;
203:         }
204: 
205:         $this->changed = true;
206: 
207:         return $ob;
208:     }
209: 
210:     /**
211:      * Saves the list of filters for the current user.
212:      *
213:      * @param array $filters  The filter list.
214:      */
215:     public function setFilters($filters)
216:     {
217:         $GLOBALS['prefs']->setValue('filter', serialize(array_values($filters)));
218:         $this->_getFilters();
219:     }
220: 
221:     /**
222:      * Loads the list of filters for the current user.
223:      */
224:     protected function _getFilters()
225:     {
226:         $filters = array();
227: 
228:         /* Build list of default filters. */
229:         $di = new DirectoryIterator(IMP_BASE . '/lib/Search/Filter');
230:         foreach ($di as $val) {
231:             if ($val->isFile()) {
232:                 $cname = 'IMP_Search_Filter_' . $val->getBasename('.php');
233:                 if (($cname != 'IMP_Search_Filter_Builtin') &&
234:                     class_exists($cname)) {
235:                     $filter = new $cname();
236:                     $filters[$filter->id] = $filter;
237:                 }
238:             }
239:         }
240: 
241:         if ($f_list = $GLOBALS['prefs']->getValue('filter')) {
242:             $f_list = @unserialize($f_list);
243:             if (is_array($f_list)) {
244:                 foreach ($f_list as $val) {
245:                     if ($val instanceof IMP_Search_Filter) {
246:                         $filters[$val->id] = $val;
247:                     }
248:                 }
249:             }
250:         }
251: 
252:         $this->_search['filters'] = $filters;
253:         $this->changed = true;
254:     }
255: 
256: 
257:     /**
258:      * Is a mailbox a filter query?
259:      *
260:      * @param string $id         The mailbox ID.
261:      * @param boolean $editable  Is this an editable (i.e. not built-in)
262:      *                           filter query?
263:      */
264:     public function isFilter($id, $editable = false)
265:     {
266:         return (isset($this->_search['filters'][$this->_strip($id)]) &&
267:                 (!$editable || $this[$id]->canEdit));
268:     }
269: 
270:     /**
271:      * Converts a filter to a search query and stores it in the local
272:      * session.
273:      *
274:      * @param string $id     The mailbox ID of the filter.
275:      * @param array $mboxes  The list of mailboxes to apply the filter on.
276:      * @param string $mid    Use as the mailbox ID.
277:      *
278:      * @return IMP_Search_Query  The created query object.
279:      * @throws InvalidArgumentException
280:      */
281:     public function applyFilter($id, array $mboxes, $mid = null)
282:     {
283:         if (!$this->isFilter($id)) {
284:             throw new InvalidArgumentException('Invalid filter ID given.');
285:         }
286: 
287:         if (!is_null($mid)) {
288:             $mid = $this->_strip($mid);
289:         }
290: 
291:         $q_ob = $this[$id]->toQuery($mboxes, $mid);
292:         $this->_search['query'][$q_ob->id] = $q_ob;
293:         $this->changed = true;
294: 
295:         return $q_ob;
296:     }
297: 
298:     /**
299:      * Saves the list of virtual folders for the current user.
300:      *
301:      * @param array $vfolders  The virtual folder list.
302:      */
303:     public function setVFolders($vfolders)
304:     {
305:         $GLOBALS['prefs']->setValue('vfolder', serialize(array_values($vfolders)));
306:         $this->_getVFolders();
307:     }
308: 
309:     /**
310:      * Loads the list of virtual folders for the current user.
311:      */
312:     protected function _getVFolders()
313:     {
314:         $vf = array();
315: 
316:         /* Build list of default virtual folders. */
317:         $di = new DirectoryIterator(IMP_BASE . '/lib/Search/Vfolder');
318:         $disable = array('IMP_Search_Vfolder_Vtrash');
319: 
320:         foreach ($di as $val) {
321:             if ($val->isFile()) {
322:                 $cname = 'IMP_Search_Vfolder_' . $val->getBasename('.php');
323:                 if (($cname != 'IMP_Search_Vfolder_Builtin') &&
324:                     class_exists($cname)) {
325:                     $vfolder = new $cname(array(
326:                         'disable' => in_array($cname, $disable)
327:                     ));
328:                     $vf[$vfolder->id] = $vfolder;
329:                 }
330:             }
331:         }
332: 
333:         if ($pref_vf = $GLOBALS['prefs']->getValue('vfolder')) {
334:             $pref_vf = @unserialize($pref_vf);
335:             if (is_array($pref_vf)) {
336:                 foreach ($pref_vf as $val) {
337:                     if ($val instanceof IMP_Search_Vfolder) {
338:                         $vf[$val->id] = $val;
339:                     }
340:                 }
341:             }
342:         }
343: 
344:         /* Only update if IMP_Imap_Tree is already initialized; otherwise,
345:          * we have a cyclic dependency. */
346:         if (IMP_Factory_Imaptree::initialized()) {
347:             $GLOBALS['injector']->getInstance('IMP_Imap_Tree')->updateVFolders($vf);
348:         }
349: 
350:         $this->_search['vfolders'] = $vf;
351:         $this->changed = true;
352:     }
353: 
354:     /**
355:      * Is a mailbox a virtual folder?
356:      *
357:      * @param string $id         The mailbox ID.
358:      * @param boolean $editable  Is this an editable (i.e. not built-in)
359:      *                           virtual folder?
360:      *
361:      * @return boolean  Whether the mailbox ID is a virtual folder.
362:      */
363:     public function isVFolder($id, $editable = false)
364:     {
365:         return (isset($this->_search['vfolders'][$this->_strip($id)]) &&
366:                 (!$editable || $this[$id]->canEdit));
367:     }
368: 
369:     /**
370:      * Determines whether a mailbox ID is the Virtual Trash Folder.
371:      *
372:      * @param string $id  The mailbox id.
373:      *
374:      * @return boolean  True if the ID is the Virtual Trash folder.
375:      */
376:     public function isVTrash($id)
377:     {
378:         return (($this->isVFolder($id)) &&
379:             ($this[$id] instanceof IMP_Search_Vfolder_Vtrash));
380:     }
381: 
382:     /**
383:      * Determines whether a mailbox ID is the Virtual INBOX Folder.
384:      *
385:      * @param string $id  The mailbox id.
386:      *
387:      * @return boolean  True if the ID is the Virtual INBOX folder.
388:      */
389:     public function isVinbox($id)
390:     {
391:         return (($this->isVFolder($id)) &&
392:             ($this[$id] instanceof IMP_Search_Vfolder_Vinbox));
393:     }
394: 
395:     /**
396:      * Is a mailbox a search query?
397:      *
398:      * @param string $id         The mailbox ID.
399:      * @param boolean $editable  Is this an editable (i.e. not built-in)
400:      *                           search query?
401:      */
402:     public function isQuery($id, $editable = false)
403:     {
404:         return (isset($this->_search['query'][$this->_strip($id)]) &&
405:                 (!$editable ||
406:                  !in_array($this[$id]->id, array(self::BASIC_SEARCH, self::DIMP_FILTERSEARCH, self::DIMP_QUICKSEARCH))));
407:     }
408: 
409:     /**
410:      * Returns a link to edit a given search query.
411:      *
412:      * @param string $id  The search query id.
413:      *
414:      * @return Horde_Url  The URL to the search page.
415:      */
416:     public function editUrl($id)
417:     {
418:         return IMP_Mailbox::get($this->createSearchId($id))->url('search.php')->add(array('edit_query' => 1));
419:     }
420: 
421:     /**
422:      * Is the given mailbox a search mailbox?
423:      *
424:      * @param string $id  The mailbox name.
425:      *
426:      * @return boolean  Whether the given mailbox name is a search mailbox.
427:      */
428:     public function isSearchMbox($id)
429:     {
430:         return (strpos($id, self::MBOX_PREFIX) === 0);
431:     }
432: 
433:     /**
434:      * Strip the identifying label from a mailbox ID.
435:      *
436:      * @param string $id  The mailbox query ID.
437:      *
438:      * @return string  The virtual folder ID, with any IMP specific
439:      *                 identifying information stripped off.
440:      */
441:     protected function _strip($id)
442:     {
443:         return $this->isSearchMbox($id)
444:             ? substr($id, strlen(self::MBOX_PREFIX))
445:             : strval($id);
446:     }
447: 
448:     /**
449:      * Create the canonical search ID for a given search query.
450:      *
451:      * @param string $id  The mailbox query ID.
452:      *
453:      * @return string  The canonical search query ID.
454:      */
455:     public function createSearchId($id)
456:     {
457:         return self::MBOX_PREFIX . $this->_strip($id);
458:     }
459: 
460:     /* ArrayAccess methods. */
461: 
462:     public function offsetExists($offset)
463:     {
464:         $id = $this->_strip($offset);
465: 
466:         foreach (array_keys($this->_search) as $key) {
467:             if (isset($this->_search[$key][$id])) {
468:                 return true;
469:             }
470:         }
471: 
472:         return false;
473:     }
474: 
475:     public function offsetGet($offset)
476:     {
477:         $id = $this->_strip($offset);
478: 
479:         foreach (array_keys($this->_search) as $key) {
480:             if (isset($this->_search[$key][$id])) {
481:                 return $this->_search[$key][$id];
482:             }
483:         }
484: 
485:         return null;
486:     }
487: 
488:     /**
489:      * Alter the current IMAP search query.
490:      *
491:      * @param string $id               The search query id.
492:      * @param IMP_Search_Query $value  The query object.
493:      *
494:      * @throws InvalidArgumentException
495:      */
496:     public function offsetSet($offset, $value)
497:     {
498:         if (!($value instanceof IMP_Search_Query)) {
499:             throw new InvalidArgumentException('$value must be a query object.');
500:         }
501: 
502:         $id = $this->_strip($offset);
503: 
504:         foreach (array_keys($this->_search) as $key) {
505:             if (isset($this->_search[$key][$id])) {
506:                 $this->_search[$key][$id] = $value;
507:                 $this->changed = true;
508: 
509:                 if ($key == 'vfolders') {
510:                     $this->setVFolders($this->_search['vfolders']);
511:                 }
512:                 return;
513:             }
514:         }
515: 
516:         throw new InvalidArgumentException('Creating search queries by array index is not supported. Use createQuery() instead.');
517:     }
518: 
519:     /**
520:      * Deletes an IMAP search query.
521:      *
522:      * @param string $id  The search query id.
523:      */
524:     public function offsetUnset($offset)
525:     {
526:         $id = $this->_strip($offset);
527: 
528:         foreach (array_keys($this->_search) as $val) {
529:             if (isset($this->_search[$val][$id])) {
530:                 unset($this->_search[$val][$id]);
531:                 $this->changed = true;
532: 
533:                 if ($val == 'vfolders') {
534:                     $this->setVFolders($this->_search['vfolders']);
535:                 }
536:                 break;
537:             }
538:         }
539:     }
540: 
541:     /* Iterator methods. */
542: 
543:     public function current()
544:     {
545:         return (($key = key($this->_search)) !== null)
546:             ? current($this->_search[$key])
547:             : null;
548:     }
549: 
550:     public function key()
551:     {
552:         return (($key = key($this->_search)) !== null)
553:             ? key($this->_search[$key])
554:             : null;
555:     }
556: 
557:     public function next()
558:     {
559:         $curr = null;
560: 
561:         while (($skey = key($this->_search)) !== null) {
562:             /* When switching between search types, need to catch the first
563:              * element of the new array. */
564:             $curr = is_null($curr)
565:                 ? next($this->_search[$skey])
566:                 : current($this->_search[$skey]);
567: 
568:             while ($curr !== false) {
569:                 if ($this->_currValid()) {
570:                     return;
571:                 }
572:                 $curr = next($this->_search[$skey]);
573:             }
574: 
575:             next($this->_search);
576:         }
577:     }
578: 
579:     public function rewind()
580:     {
581:         foreach (array_keys($this->_search) as $key) {
582:             reset($this->_search[$key]);
583:         }
584:         reset($this->_search);
585: 
586:         if ($this->valid() && !$this->_currValid()) {
587:             $this->next();
588:         }
589:     }
590: 
591:     public function valid()
592:     {
593:         return (key($this->_search) !== null);
594:     }
595: 
596:     /* Helper functions for Iterator methods. */
597: 
598:     /**
599:      * Set the current iterator filter and reset the internal pointer.
600:      *
601:      * @param integer $mask  A mask with the following possible elements:
602:      * <pre>
603:      * IMP_Search::LIST_FILTER
604:      * IMP_Search::LIST_QUERY
605:      * IMP_Search::LIST_VFOLDER
606:      * </pre>
607:      */
608:     public function setIteratorFilter($mask = 0)
609:     {
610:         $this->_filter = $mask;
611:         reset($this);
612:     }
613: 
614:     /**
615:      * Returns true if the current object is valid given the current filter.
616:      *
617:      * @return boolean  True if the object should be displayed.
618:      */
619:     protected function _currValid()
620:     {
621:         if (!($ob = $this->current())) {
622:             return false;
623:         }
624: 
625:         if ($ob->enabled ||
626:             ($this->_filter & self::LIST_DISABLED)) {
627:             if (!$this->_filter) {
628:                 return true;
629:             }
630: 
631:             if (($this->_filter & self::LIST_FILTER) &&
632:                 $this->isFilter($ob)) {
633:                 return true;
634:             }
635: 
636:             if (($this->_filter & self::LIST_QUERY) &&
637:                 $this->isQuery($ob)) {
638:                 return true;
639:             }
640: 
641:             if (($this->_filter & self::LIST_VFOLDER) &&
642:                 $this->isVFolder($ob)) {
643:                 return true;
644:             }
645:         }
646: 
647:         return false;
648:     }
649: 
650:     /* Serializable methods. */
651: 
652:     /**
653:      * Serialize.
654:      *
655:      * @return string  Serialized representation of this object.
656:      */
657:     public function serialize()
658:     {
659:         return serialize($this->_search);
660:     }
661: 
662:     /**
663:      * Unserialize.
664:      *
665:      * @param string $data  Serialized data.
666:      *
667:      * @throws Exception
668:      */
669:     public function unserialize($data)
670:     {
671:         $data = @unserialize($data);
672:         if (!is_array($data)) {
673:             throw new Exception('Cache version change');
674:         }
675: 
676:         $this->_search = $data;
677:     }
678: 
679: }
680: 
API documentation generated by ApiGen