removes wildcard handling in text filter for in/notin operators
[tine20] / tine20 / Tinebase / Model / Filter / Text.php
1 <?php
2 /**
3  * Tine 2.0
4  * 
5  * @package     Tinebase
6  * @subpackage  Filter
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL Version 3
8  * @copyright   Copyright (c) 2007-2013 Metaways Infosystems GmbH (http://www.metaways.de)
9  * @author      Cornelius Weiss <c.weiss@metaways.de>
10  */
11
12 /**
13  * Tinebase_Model_Filter_Text
14  * 
15  * filters one filterstring in one property
16  * 
17  * @package     Tinebase
18  * @subpackage  Filter
19  */
20 class Tinebase_Model_Filter_Text extends Tinebase_Model_Filter_Abstract
21 {
22     /**
23      * @var array list of allowed operators
24      */
25     protected $_operators = array(
26         0 => 'equals',
27         1 => 'contains',
28         2 => 'startswith',
29         3 => 'endswith',
30         4 => 'not',
31         5 => 'in',
32         6 => 'notin',
33         7 => 'isnull',
34         8 => 'notnull',
35         // add 'group by _fieldname_' to select statement and remove empty values / filter value is not used when this operator is set
36         9 => 'group',
37
38         // filter replace space and - with %
39         10 => 'equalsspecial'
40     );
41     
42     /**
43      * @var array maps abstract operators to sql operators
44      * filled in constructor
45      */
46     protected $_opSqlMap = array();
47
48     /**
49      * get a new single filter action
50      *
51      * @param string|array $_fieldOrData
52      * @param string $_operator
53      * @param mixed  $_value
54      * @param array  $_options
55      *
56      * @todo remove legacy code + obsolete params sometimes
57      */
58     public function __construct($_fieldOrData, $_operator = NULL, $_value = NULL, array $_options = array())
59     {
60         $this->_setOpSqlMap();
61         parent::__construct($_fieldOrData, $_operator, $_value, $_options);
62     }
63     
64     /**
65      * set operator sql map (need to do this here because of Tinebase_Backend_Sql_Commands)
66      */
67     protected function _setOpSqlMap()
68     {
69         $db = Tinebase_Core::getDb();
70         $this->_opSqlMap = array(
71             'equals'            => array('sqlop' => ' LIKE ' . Tinebase_Backend_Sql_Command::factory($db)->prepareForILike('(?)'),          'wildcards' => '?'  ),
72             'contains'          => array('sqlop' => ' LIKE ' . Tinebase_Backend_Sql_Command::factory($db)->prepareForILike('(?)'),          'wildcards' => '%?%'),
73             'startswith'        => array('sqlop' => ' LIKE ' . Tinebase_Backend_Sql_Command::factory($db)->prepareForILike('(?)'),          'wildcards' => '?%' ),
74             'endswith'          => array('sqlop' => ' LIKE ' . Tinebase_Backend_Sql_Command::factory($db)->prepareForILike('(?)'),          'wildcards' => '%?' ),
75             'not'               => array('sqlop' => ' NOT LIKE ' . Tinebase_Backend_Sql_Command::factory($db)->prepareForILike('(?)'),      'wildcards' => '?'  ),
76             'in'                => array('sqlop' => ' IN (?)',          'wildcards' => '?'  ),
77             'notin'             => array('sqlop' => ' NOT IN (?)',      'wildcards' => '?'  ),
78             'isnull'            => array('sqlop' => ' IS NULL',         'wildcards' => '?'  ),
79             'notnull'           => array('sqlop' => ' IS NOT NULL',     'wildcards' => '?'  ),
80             'group'             => array('sqlop' => " NOT LIKE  ''",    'wildcards' => '?'  ),
81             'equalsspecial'     => array('sqlop' => ' LIKE ' . Tinebase_Backend_Sql_Command::factory($db)->prepareForILike('(?)'),          'wildcards' => '?'     ),
82         );
83     }
84
85     /**
86      * appends sql to given select statement
87      *
88      * @param  Zend_Db_Select                $_select
89      * @param  Tinebase_Backend_Sql_Abstract $_backend
90      * @throws Tinebase_Exception_InvalidArgument
91      */
92     public function appendFilterSql($_select, $_backend)
93     {
94         // quote field identifier, set action and replace wildcards
95         $field = $this->_getQuotedFieldName($_backend);
96         
97         if (! (isset($this->_opSqlMap[$this->_operator]) || array_key_exists($this->_operator, $this->_opSqlMap))) {
98             throw new Tinebase_Exception_InvalidArgument('Operator "' . $this->_operator . '" not defined in sql map of ' . get_class($this));
99         }
100         $action = $this->_opSqlMap[$this->_operator];
101         
102         // don't remove wildcards for certain operators
103         // TODO add an option for this?
104         $value = (! in_array($this->_operator, array('in', 'notin'))) ? $this->_replaceWildcards($this->_value) : $this->_value;
105         
106         // check if group by is operator and return if this is the case
107         if ($this->_operator == 'group') {
108             $_select->group($this->_field);
109         }
110         
111         if (in_array($this->_operator, array('in', 'notin')) && ! is_array($value)) {
112             $value = explode(' ', $value);
113         }
114         
115         $db = Tinebase_Core::getDb();
116                 
117         if (is_array($value) && empty($value)) {
118              $_select->where('1=' . (substr($this->_operator, 0, 3) == 'not' ? '1/* empty query */' : '0/* impossible query */'));
119              return;
120         }
121         
122         if ($this->_operator == 'equalsspecial') {
123             if (is_array($value)) {
124                 foreach($value as $key => $v){
125                     $value[$key] = preg_replace('/(\s+|\-)/', '%', $v);
126                 }
127             }
128             else {
129                 $value = preg_replace('/(\s+|\-)/', '%', $value);
130             }  
131         }
132         
133         if (! in_array($this->_operator, array('in', 'notin'))) {
134             $where = Tinebase_Core::getDb()->quoteInto(Tinebase_Backend_Sql_Command::factory($db)->prepareForILike($field) . ' ' . $action['sqlop'], $value);
135         } else {
136             $where = Tinebase_Core::getDb()->quoteInto($field . $action['sqlop'], $value);
137         }
138
139         if (in_array($this->_operator, array('not', 'notin')) && $value !== '') {
140             $where = "( $where OR $field IS NULL)";
141         }
142
143         if (in_array($this->_operator, array('equals', 'equalsspecial', 'contains', 'startswith', 'endswith', 'in')) && $value === '') {
144             $where = "( $where OR $field IS NULL)";
145         }
146
147         // finally append query to select object
148         $_select->where($where);
149     }
150 }