Completed
Push — master ( b50965...7366f7 )
by Patrick
06:04
created

FilterClause::toMongoFilter()   C

Complexity

Conditions 7
Paths 24

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 17
c 1
b 0
f 0
nc 24
nop 0
dl 0
loc 27
rs 6.7272
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
        $this->var2 = trim($this->var2, "'");
199
        if($this->var1 === '_id')
200
        {
201
            $this->var2 = new \MongoId($this->var2);
202
        }
203
        switch($this->op)
204
        {
205
            case '=':
206
                return array($this->var1=>$this->var2);
207
            case 'substringof':
208
                return array($this->var1=>array('$regex'=>new \MongoRegex('/'.$this->var2.'/i')));
209
            case 'indexof':
210
                return $this->getMongoIndexOfOperator();
211
            default:
212
                return array($this->var1=>$this->getMongoClauseArray($this->op, $this->var2));
213
        }
214
    }
215
216
    public function php_compare($value)
217
    {
218
        switch($this->op)
219
        {
220
            case '!=':
221
                return $value != $this->var2;
222
            case '=':
223
                return $value == $this->var2;
224
            case '<':
225
                return $value < $this->var2;
226
            case '<=':
227
                return $value <= $this->var2;
228
            case '>':
229
                return $value > $this->var2;
230
            case '>=':
231
                return $value >= $this->var2;
232
        }
233
    }
234
}
235