ca5cb0ec32ceedc6663b2da9ad86ad924f08ce3a
[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         $value = $this->_replaceWildcards($this->_value);
102
103         // check if group by is operator and return if this is the case
104         if ($this->_operator == 'group') {
105             $_select->group($this->_field);
106         }
107
108         if (in_array($this->_operator, array('in', 'notin')) && ! is_array($value)) {
109             $value = explode(' ', $value);
110         }
111         
112         $db = Tinebase_Core::getDb();
113                 
114         if (is_array($value) && empty($value)) {
115              $_select->where('1=' . (substr($this->_operator, 0, 3) == 'not' ? '1/* empty query */' : '0/* impossible query */'));
116              return;
117         }
118         
119         if ($this->_operator == 'equalsspecial') {
120             if (is_array($value)) {
121                 foreach($value as $key => $v){
122                     $value[$key] = preg_replace('/(\s+|\-)/', '%', $v);
123                 }
124             }
125             else {
126                 $value = preg_replace('/(\s+|\-)/', '%', $value);
127             }  
128         }
129         
130         if (! in_array($this->_operator, array('in', 'notin'))) {
131             $where = Tinebase_Core::getDb()->quoteInto(Tinebase_Backend_Sql_Command::factory($db)->prepareForILike($field) . ' ' . $action['sqlop'], $value);
132         }
133         else {
134             $where = Tinebase_Core::getDb()->quoteInto($field . $action['sqlop'], $value);
135         }
136
137         if (in_array($this->_operator, array('not', 'notin')) && $value !== '') {
138             $where = "( $where OR $field IS NULL)";
139         }
140
141         if (in_array($this->_operator, array('equals', 'equalsspecial', 'contains', 'startswith', 'endswith', 'in')) && $value === '') {
142             $where = "( $where OR $field IS NULL)";
143         }
144
145         // finally append query to select object
146         $_select->where($where);
147     }
148 }