Completed
Push — master ( 88cd01...d90095 )
by Patrick
03:03
created

FilterClause::opToMongo()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 18
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 14
c 1
b 0
f 0
nc 6
nop 1
dl 0
loc 18
rs 8.8571
1
<?php
2
namespace Data;
3
4
class FilterClause
5
{
6
    public $var1;
7
    public $var2;
8
    public $op;
9
10
    function __construct($string = false)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
11
    {
12
        if($string !== false)
13
        {
14
            $this->process_filter_string($string);
0 ignored issues
show
Documentation introduced by
$string is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
15
        }
16
    }
17
18
    /**
19
     * Find the string inside the other string
20
     *
21
     * @param string $haystack The string to search inside
22
     * @param string $needle The string to search for
23
     *
24
     * @return boolean True if the needle exists in the haystack, false otherwise
25
     */
26
    static function str_startswith($haystack, $needle)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
27
    {
28
        return substr($haystack, 0, strlen($needle)) === $needle;
29
    }
30
31
    protected function filterIsFunction($string)
32
    {
33
        return (self::str_startswith($string, 'substringof') || self::str_startswith($string, 'contains') ||
34
                self::str_startswith($string, 'indexof'));
35
    }
36
37
    protected function odataOpToStd($op)
38
    {
39
        switch($op)
40
        {
41
            case 'ne':
42
                return '!=';
43
            case 'eq':
44
                return '=';
45
            case 'lt':
46
                return '<';
47
            case 'le':
48
                return '<=';
49
            case 'gt':
50
                return '>';
51
            case 'ge':
52
                return '>=';
53
            default:
54
                return $op;
55
        }
56
    }
57
58
    /**
59
     * Convert the string into an OData Filter
60
     *
61
     * @param string $string The string to turn into a filter
62
     */
63
    protected function process_filter_string($string)
64
    {
65
        if($this->filterIsFunction($string))
66
        {
67
            $this->op   = strtok($string, '(');
68
            $this->var1 = strtok(',');
69
            $this->var2 = trim(strtok(')'));
70
            return;
71
        }
72
        $field = strtok($string, ' ');
73
        $op = strtok(' ');
74
        $rest = strtok("\0");
75
        $this->var1  = $field;
76
        $this->op    = $this->odataOpToStd($op);
77
        $this->var2  = $rest;
78
    }
79
80
    public function to_sql_string()
81
    {
82
        switch($this->op)
83
        {
84
            case 'substringof':
85
            case 'contains':
86
                return $this->var1.' LIKE \'%'.trim($this->var2, "'").'%\'';
87
                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...
88
            default:
89
                return $this->var1.$this->op.$this->var2;
90
                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...
91
        }
92
    }
93
94
    public function to_ldap_string()
95
    {
96
        $str = '(';
97
        switch($this->op)
98
        {
99
            case 'substringof':
100
            case 'contains':
101
                $str .= $this->var1.$this->op.'*'.trim($this->var2, "'").'*';
102
                break;
103
            case '!=':
104
                $str .= '!('.$this->var1.'='.$this->var2.')';
105
                break;
106
            default:
107
                $str .= $this->var1.$this->op.$this->var2;
108
                break;
109
        }
110
        return $str.')';
111
    }
112
113
    private function getMongoIndexOfOperator()
114
    {
115
        $field = $this->var1;
116
        $case  = false;
117
        if(self::str_startswith($this->var1, 'tolower'))
118
        {
119
            $field = substr($this->var1, strpos($this->var1, '(') + 1);
120
            $field = substr($field, 0, strpos($field, ')'));
121
            $case = true;
122
        }
123
        if($case)
124
        {
125
            return array($field=>array('$regex'=>new \MongoRegex('/'.$this->var2.'/i')));
126
        }
127
        return array($field=>$this->var2);       
128
    }
129
130
    private function opToMongo($op)
131
    {
132
        switch($op)
133
        {
134
            case '!=':
135
                return '$ne';
136
            case '<';
137
                return '$lt';
138
            case '<=':
139
                return '$lte';
140
            case '>':
141
                return '$gt';
142
            case '>=':
143
                return '$gte';
144
            default:
145
                return $op;
146
        }
147
    }
148
149
    private function getMongoClauseArray($op, $var2)
150
    {
151
        return array($this->opToMongo($op)=>$var2);
152
    }
153
154
    public function toMongoFilter()
155
    {
156
        $this->var2 = trim($this->var2, "'");
157
        if($this->var1 === '_id')
158
        {
159
            $this->var2 = new \MongoId($this->var2);
160
        }
161
        switch($this->op)
162
        {
163
            case '=':
164
                return array($this->var1=>$this->var2);
165
            case 'substringof':
166
                return array($this->var1=>array('$regex'=>new MongoRegex('/'.$this->var2.'/i')));
167
            case 'indexof':
168
                return $this->getMongoIndexOfOperator();
169
            default:
170
                return array($this->var1=>$this->getMongoClauseArray($this->op, $this->var2));
171
        }
172
    }
173
174
    function php_compare($value)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
175
    {
176
        switch($this->op)
177
        {
178
            case '!=':
179
                return $value != $this->var2;
180
            case '=':
181
                return $value == $this->var2;
182
            case '<':
183
                return $value < $this->var2;
184
            case '<=':
185
                return $value <= $this->var2;
186
            case '>':
187
                return $value > $this->var2;
188
            case '>=':
189
                return $value >= $this->var2;
190
        }
191
    }
192
}
193