Files
server/usr/share/psa-horde/imp/lib/Search/Query.php
2026-01-07 20:52:11 +01:00

384 lines
10 KiB
PHP

<?php
/**
* Copyright 2010-2017 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (GPL). If you
* did not receive this file, see http://www.horde.org/licenses/gpl.
*
* @copyright 2010-2017 Horde LLC
* @category Horde
* @license http://www.horde.org/licenses/gpl GPL
* @package IMP
*/
/**
* Data structure for a search query.
*
* @author Michael Slusarz <slusarz@horde.org>
* @category Horde
* @copyright 2010-2017 Horde LLC
* @license http://www.horde.org/licenses/gpl GPL
* @package IMP
*
* @property boolean $all Does this query search all mailboxes?
* @property boolean $canEdit Can this query be edited?
* @property string $formid The mailbox ID to use in forms.
* @property string $id The query ID.
* @property string $label The query label.
* @property array $mboxes The list of mailboxes to query. This list
* automatically expands subfolder searches.
* @property array $mbox_list The list of individual mailboxes to query (no
* subfolder mailboxes).
* @property IMP_Mailbox $mbox_ob The IMP_Mailbox object for this query.
* @property string $mid The query ID with the search mailbox prefix.
* @property array $query The list of IMAP queries that comprise this search.
* Keys are mailbox names, values are
* Horde_Imap_Client_Search_Query objects.
* @property string $querytext The textual representation of the query.
* @property array $subfolder_list The list of mailboxes to do subfolder
* queries for. The subfolders are not
* expanded.
*/
class IMP_Search_Query implements Serializable
{
/* Serialized version. */
const VERSION = 1;
/* Prefix indicating subfolder search. */
const SUBFOLDER = "sub\0";
/* Mailbox value indicating a search all mailboxes search. */
const ALLSEARCH = "all\0";
/**
* Is this query enabled?
*
* @var boolean
*/
public $enabled = true;
/**
* Cache results.
*
* @var array
*/
protected $_cache = array();
/**
* Can this query be edited?
*
* @var boolean
*/
protected $_canEdit = true;
/**
* The search criteria (IMP_Search_Element objects).
*
* @var array
*/
protected $_criteria = array();
/**
* The search ID.
*
* @var string
*/
protected $_id;
/**
* The virtual folder label.
*
* @var string
*/
protected $_label;
/**
* The mailbox list.
*
* @var array
*/
protected $_mboxes = array();
/**
* List of serialize entries not to save.
*
* @var array
*/
protected $_nosave = array();
/**
* Constructor.
*
* @var array $opts Options:
* - add: (array) A list of criteria to add (Horde_Search_Element
* objects).
* DEFAULT: No criteria explicitly added.
* - all: (boolean) Search all mailboxes? If set, ignores 'mboxes' and
* 'subfolders' options.
* DEFAULT: false
* - disable: (boolean) Disable this query?
* DEFAULT: false
* - id: (string) Use this ID.
* DEFAULT: ID automatically generated.
* - label: (string) The label for this query.
* DEFAULT: Search Results
* - mboxes: (array) The list of mailboxes to search.
* DEFAULT: None
* - subfolders: (array) The list of mailboxes to do subfolder searches
* for.
* DEFAULT: None
*/
public function __construct(array $opts = array())
{
$this->enabled = empty($opts['disable']);
if (isset($opts['add'])) {
$this->replace($opts['add']);
}
$this->_id = isset($opts['id'])
? $opts['id']
: strval(new Horde_Support_Randomid());
$this->_label = isset($opts['label'])
? $opts['label']
: _("Search Results");
if (!empty($opts['all'])) {
$this->_mboxes = array(self::ALLSEARCH);
} else {
if (isset($opts['mboxes'])) {
$this->_mboxes = $opts['mboxes'];
}
if (isset($opts['subfolders'])) {
foreach ($opts['subfolders'] as $val) {
$this->_mboxes[] = self::SUBFOLDER . $val;
}
}
natsort($this->_mboxes);
}
}
/**
*/
public function __get($name)
{
global $injector;
switch ($name) {
case 'all':
return in_array(self::ALLSEARCH, $this->_mboxes);
case 'canEdit':
return $this->_canEdit;
case 'criteria':
$out = array();
foreach ($this->_criteria as $elt) {
$out[] = array(
'criteria' => $elt->getCriteria(),
'element' => get_class($elt)
);
}
return $out;
case 'formid':
return $this->mbox_ob->form_to;
case 'id':
return $this->_id;
case 'label':
return $this->_label;
case 'mboxes':
if (!isset($this->_cache['mboxes'])) {
$out = $this->mbox_list;
if (!$this->all &&
($s_list = $this->subfolder_list)) {
foreach ($s_list as $val) {
$out = array_merge($out, $val->subfolders);
}
}
$this->_cache['mboxes'] = array_unique($out, SORT_REGULAR);
}
return $this->_cache['mboxes'];
case 'mbox_list':
case 'subfolder_list':
if (!isset($this->_cache['mbox_list'])) {
$mbox = $subfolder = array();
if ($this->all) {
$mbox = array();
$iterator = new IMP_Ftree_IteratorFilter(
$injector->getInstance('IMP_Ftree')
);
$iterator->add(array(
$iterator::CONTAINERS,
$iterator::NONIMAP
));
foreach ($iterator as $val) {
$mbox[] = $val->mbox_ob;
}
} else {
foreach ($this->_mboxes as $val) {
if (strpos($val, self::SUBFOLDER) === 0) {
$subfolder[] = IMP_Mailbox::get(substr($val, strlen(self::SUBFOLDER)));
} else {
$mbox[] = IMP_Mailbox::get($val);
}
}
}
$this->_cache['mbox_list'] = $mbox;
$this->_cache['subfolder_list'] = $subfolder;
}
return $this->_cache[$name];
case 'mbox_ob':
return IMP_Mailbox::get($this->mid);
case 'mid':
return IMP_Search::MBOX_PREFIX . $this->_id;
case 'query':
$qout = array();
foreach ($this->mboxes as $mbox) {
$query = new Horde_Imap_Client_Search_Query();
foreach ($this->_criteria as $elt) {
$query = $elt->createQuery($mbox, $query);
}
$qout[strval($mbox)] = $query;
}
return $qout;
case 'querytext':
$text = array();
foreach ($this->_criteria as $elt) {
if ($elt instanceof IMP_Search_Element_Or) {
array_pop($text);
$text[] = $elt->queryText();
} else {
$text[] = $elt->queryText();
$text[] = _("and");
}
}
array_pop($text);
$mbox_display = array();
if ($this->all) {
$mbox_display[] = _("All Mailboxes");
} else {
foreach ($this->mboxes as $val) {
$mbox_display[] = $val->display;
}
}
return sprintf(_("Search %s in %s"), implode(' ', $text), '[' . implode(', ', $mbox_display) . ']');
}
}
/**
* String representation of this object: the mailbox ID.
*
* @return string Mailbox ID.
*/
public function __toString()
{
return $this->mid;
}
/**
* Add a search query element.
*
* @param IMP_Search_Element $elt The search element to add.
*/
public function add(IMP_Search_Element $elt)
{
$this->_criteria[] = $elt;
}
/**
* Replace the search query with the given query.
*
* @param array $criteria A list of criteria to add (Horde_Search_Element
* objects).
*/
public function replace(array $criteria = array())
{
$this->_criteria = array();
foreach ($criteria as $val) {
$this->add($val);
}
}
/* Serializable methods. */
/**
* Serialization.
*
* @return string Serialized data.
*/
public function serialize()
{
$data = array_filter(array(
'c' => $this->_criteria,
'e' => intval($this->enabled),
'i' => $this->_id,
'l' => $this->_label,
'm' => $this->_mboxes,
'v' => self::VERSION
));
foreach ($this->_nosave as $val) {
unset($data[$val]);
}
return serialize($data);
}
/**
* Unserialization.
*
* @param string $data Serialized data.
*
* @throws Exception
*/
public function unserialize($data)
{
$data = unserialize($data);
if (!is_array($data) ||
!isset($data['v']) ||
($data['v'] != self::VERSION)) {
throw new Exception('Cache version change');
}
if (isset($data['c'])) {
$this->_criteria = $data['c'];
}
$this->enabled = !empty($data['e']);
if (isset($data['i'])) {
$this->_id = $data['i'];
}
if (isset($data['l'])) {
$this->_label = $data['l'];
}
if (isset($data['m'])) {
$this->_mboxes = $data['m'];
}
}
}