Completed
Push — develop ( 18ee8c...489265 )
by Patrick
09:31 queued 06:48
created

FilterClause::toMongoFilter()   C

Complexity

Conditions 7
Paths 24

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 18
nc 24
nop 0
dl 0
loc 30
rs 6.7272
c 1
b 0
f 0
1
<?php
2
namespace Data;
3
4
class FilterClause
5
{
6
    public $var1;
7
    public $var2;
8
    public $op;
9
10
    /**
11
     * Create a filter clause from the string
12
     *
13
     * @param string $string The filter clause string
14
     */
15
    public function __construct($string = false)
16
    {
17
        if(is_string($string))
18
        {
19
            $this->process_filter_string($string);
20
        }
21
    }
22
23
    /**
24
     * Find the string inside the other string
25
     *
26
     * @param string $haystack The string to search inside
27
     * @param string $needle The string to search for
28
     *
29
     * @return boolean True if the needle exists in the haystack, false otherwise
30
     */
31
    protected static function str_startswith($haystack, $needle)
32
    {
33
        return substr($haystack, 0, strlen($needle)) === $needle;
34
    }
35
36
    /**
37
     * Is the specified filter a function?
38
     *
39
     * @param string $string The filter clause
40
     *
41
     * @return boolean True if the filter is an operation, false otherwise
42
     */
43
    protected function filterIsFunction($string)
44
    {
45
        return (self::str_startswith($string, 'substringof') || self::str_startswith($string, 'contains') ||
46
                self::str_startswith($string, 'indexof'));
47
    }
48
49
    /**
50
     * Convert the OData simple op to standard operations
51
     *
52
     * @param string $op The OData op
53
     *
54
     * @return string The standard programatic notation
55
     */
56
    protected function odataOpToStd($op)
57
    {
58
        switch($op)
59
        {
60
            case 'ne':
61
                return '!=';
62
            case 'eq':
63
                return '=';
64
            case 'lt':
65
                return '<';
66
            case 'le':
67
                return '<=';
68
            case 'gt':
69
                return '>';
70
            case 'ge':
71
                return '>=';
72
            default:
73
                return $op;
74
        }
75
    }
76
77
    /**
78
     * Convert the string into an OData Filter
79
     *
80
     * @param string $string The string to turn into a filter
81
     */
82
    protected function process_filter_string($string)
83
    {
84
        if($this->filterIsFunction($string))
85
        {
86
            $this->op   = strtok($string, '(');
87
            $this->var1 = strtok(',');
88
            $this->var2 = trim(strtok(')'));
89
            return;
90
        }
91
        $field = strtok($string, ' ');
92
        $op = strtok(' ');
93
        $rest = strtok("\0");
94
        $this->var1  = $field;
95
        $this->op    = $this->odataOpToStd($op);
96
        $this->var2  = $rest;
97
    }
98
99
    public function to_sql_string()
100
    {
101
        switch($this->op)
102
        {
103
            case 'substringof':
104
            case 'contains':
105
                return $this->var1.' LIKE \'%'.trim($this->var2, "'").'%\'';
106
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
107
            default:
108
                return $this->var1.$this->op.$this->var2;
109
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
110
        }
111
    }
112
113
    public function to_ldap_string()
114
    {
115
        $str = '(';
116
        switch($this->op)
117
        {
118
            case 'substringof':
119
            case 'contains':
120
                $str .= $this->var1.$this->op.'*'.trim($this->var2, "'").'*';
121
                break;
122
            case '!=':
123
                $str .= '!('.$this->var1.'='.$this->var2.')';
124
                break;
125
            default:
126
                $str .= $this->var1.$this->op.$this->var2;
127
                break;
128
        }
129
        return $str.')';
130
    }
131
132
    private function getMongoIndexOfOperator()
133
    {
134
        $field = $this->var1;
135
        $case  = false;
136
        if(self::str_startswith($this->var1, 'tolower'))
137
        {
138
            $field = substr($this->var1, strpos($this->var1, '(') + 1);
139
            $field = substr($field, 0, strpos($field, ')'));
140
            $case = true;
141
        }
142
        if($case)
143
        {
144
            return array($field=>array('$regex'=>new \MongoRegex('/'.$this->var2.'/i')));
145
        }
146
        return array($field=>$this->var2);       
147
    }
148
149
    /**
150
     * Convert the standard operations to Mongo operations
151
     *
152
     * @param string $op The standard op
153
     *
154
     * @return string The mongo operator
155
     */
156
    private function opToMongo($op)
157
    {
158
        switch($op)
159
        {
160
            case '!=':
161
                return '$ne';
162
            case '<';
163
                return '$lt';
164
            case '<=':
165
                return '$lte';
166
            case '>':
167
                return '$gt';
168
            case '>=':
169
                return '$gte';
170
            default:
171
                return $op;
172
        }
173
    }
174
175
    /**
176
     * Convert the right hand side of the filter clause into an Mongo array
177
     *
178
     * @param string $op The standard operator
179
     * @param string $var The second variable in the operator
0 ignored issues
show
Bug introduced by
There is no parameter named $var. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
180
     *
181
     * @return array An array of mongo operations
182
     */
183
    private function getMongoClauseArray($op, $var2)
184
    {
185
        return array($this->opToMongo($op)=>$var2);
186
    }
187
188
    public function toMongoFilter()
189
    {
190
        if($this->var2 === 'true')
191
        {
192
            $this->var2 = true;
193
        }
194
        else if($this->var2 === 'false')
195
        {
196
            $this->var2 = false;
197
        }
198
        else
199
        {
200
            $this->var2 = trim($this->var2, "'");
201
        }
202
        if($this->var1 === '_id')
203
        {
204
            $this->var2 = new \MongoId($this->var2);
205
        }
206
        switch($this->op)
207
        {
208
            case '=':
209
                return array($this->var1=>$this->var2);
210
            case 'substringof':
211
                return array($this->var1=>array('$regex'=>new \MongoRegex('/'.$this->var2.'/i')));
212
            case 'indexof':
213
                return $this->getMongoIndexOfOperator();
214
            default:
215
                return array($this->var1=>$this->getMongoClauseArray($this->op, $this->var2));
216
        }
217
    }
218
219
    public function php_compare($value)
220
    {
221
        switch($this->op)
222
        {
223
            case '!=':
224
                return $value != $this->var2;
225
            case '=':
226
                return $value == $this->var2;
227
            case '<':
228
                return $value < $this->var2;
229
            case '<=':
230
                return $value <= $this->var2;
231
            case '>':
232
                return $value > $this->var2;
233
            case '>=':
234
                return $value >= $this->var2;
235
        }
236
    }
237
}
238