Completed
Push — master ( 65c142...fadeb9 )
by Patrick
02:06
created

FilterClause::toMongoFilter()   C

Complexity

Conditions 11
Paths 144

Size

Total Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
nc 144
nop 0
dl 0
loc 52
rs 6.6072
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 View Code Duplication
            case 'contains':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 View Code Duplication
            case 'contains':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
120
                $str .= $this->var1.'=*'.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 if(is_numeric($this->var2))
199
        {
200
            $this->var2 = intval($this->var2);
201
        }
202
        else
203
        {
204
            $this->var2 = trim($this->var2, "'");
205
        }
206
        if($this->var1 === '_id')
207
        {
208
            try
209
            {
210
                if(class_exists('MongoId'))
211
                {
212
                    $this->var2 = new \MongoId($this->var2);
213
                }
214
                else
215
                {
216
                    $this->var2 = new \MongoDB\BSON\ObjectId($this->var2);
217
                }
218
            }
219
            catch(\MongoException $e)
220
            {
221
                //Not a valid mongo ID. Just leave the variable alone and try the query...
222
            }
223
            catch(\MongoDB\Driver\Exception\InvalidArgumentException $e)
0 ignored issues
show
Bug introduced by
The class MongoDB\Driver\Exception\InvalidArgumentException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
224
            {
225
                //Not a valid mongo ID. Just leave the variable alone and try the query...
226
            }
227
        }
228
        switch($this->op)
229
        {
230
            case '=':
231
                return array($this->var1=>$this->var2);
232
            case 'substringof':
233
                return array($this->var1=>array('$regex'=>new \MongoRegex('/'.$this->var2.'/i')));
234
            case 'indexof':
235
                return $this->getMongoIndexOfOperator();
236
            default:
237
                return array($this->var1=>$this->getMongoClauseArray($this->op, $this->var2));
238
        }
239
    }
240
241
    public function php_compare($value)
242
    {
243
	if(is_array($value))
244
	{
245
            return $this->php_compare($value[$this->var1]);
246
	}
247
        switch($this->op)
248
        {
249
            case '!=':
250
                return $value != $this->var2;
251
	    case '=':
252
                return $value == $this->var2;
253
            case '<':
254
                return $value < $this->var2;
255
            case '<=':
256
                return $value <= $this->var2;
257
            case '>':
258
                return $value > $this->var2;
259
            case '>=':
260
                return $value >= $this->var2;
261
        }
262
    }
263
}
264