jamesmoss /
flywheel
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | namespace JamesMoss\Flywheel; |
||
| 4 | |||
| 5 | /** |
||
| 6 | * Query |
||
| 7 | * |
||
| 8 | * Builds an executes a query whichs searches and sorts documents from a |
||
| 9 | * repository. |
||
| 10 | */ |
||
| 11 | class QueryExecuter |
||
| 12 | { |
||
| 13 | protected $repo; |
||
| 14 | protected $predicate; |
||
| 15 | protected $limit; |
||
| 16 | protected $orderBy; |
||
| 17 | |||
| 18 | /** |
||
| 19 | * Constructor |
||
| 20 | * |
||
| 21 | * @param Repository $repo The repo to execute against |
||
| 22 | * @param Predicate $pred The predicate to use. |
||
| 23 | * @param array $limit The count and offset. |
||
| 24 | * @param array $orderBy An array of field names to order by |
||
| 25 | */ |
||
| 26 | 13 | public function __construct(Repository $repo, Predicate $pred, array $limit, array $orderBy) |
|
| 27 | { |
||
| 28 | 13 | $this->repo = $repo; |
|
| 29 | 13 | $this->predicate = $pred; |
|
| 30 | 13 | $this->limit = $limit; |
|
| 31 | 13 | $this->orderBy = $orderBy; |
|
| 32 | 13 | } |
|
| 33 | |||
| 34 | /** |
||
| 35 | * Runs the query. |
||
| 36 | * |
||
| 37 | * @return Result The documents returned from this query. |
||
| 38 | */ |
||
| 39 | 13 | public function run() |
|
| 40 | { |
||
| 41 | 13 | $documents = $this->repo->findAll(); |
|
| 42 | |||
| 43 | 13 | if ($predicates = $this->predicate->getAll()) { |
|
| 44 | 10 | $documents = $this->filter($documents, $predicates); |
|
| 45 | 10 | } |
|
| 46 | |||
| 47 | 13 | if ($this->orderBy) { |
|
|
0 ignored issues
–
show
|
|||
| 48 | 4 | $sorts = array(); |
|
| 49 | 4 | foreach ($this->orderBy as $order) { |
|
| 50 | 4 | $parts = explode(' ', $order, 2); |
|
| 51 | // TODO - validate parts |
||
| 52 | 4 | $sorts[] = array( |
|
| 53 | 4 | $parts[0], |
|
| 54 | 4 | isset($parts[1]) && $parts[1] == 'DESC' ? SORT_DESC : SORT_ASC |
|
| 55 | 4 | ); |
|
| 56 | 4 | } |
|
| 57 | |||
| 58 | 4 | $documents = $this->sort($documents, $sorts); |
|
| 59 | 4 | } |
|
| 60 | |||
| 61 | 13 | $totalCount = count($documents); |
|
| 62 | |||
| 63 | 13 | if ($this->limit) { |
|
|
0 ignored issues
–
show
The expression
$this->limit of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using Loading history...
|
|||
| 64 | list($count, $offset) = $this->limit; |
||
| 65 | $documents = array_slice($documents, $offset, $count); |
||
| 66 | } |
||
| 67 | |||
| 68 | 13 | return new Result(array_values($documents), $totalCount); |
|
| 69 | } |
||
| 70 | |||
| 71 | 11 | public function getFieldValue($doc, $field, &$found = false) |
|
| 72 | { |
||
| 73 | 11 | $found = false; |
|
| 74 | |||
| 75 | 11 | if ($field === '__id') { |
|
| 76 | 1 | $found = true; |
|
| 77 | |||
| 78 | 1 | return $doc->getId(); |
|
| 79 | } |
||
| 80 | |||
| 81 | 10 | if (false !== strpos($field, '.')) { |
|
| 82 | 5 | return $doc->getNestedProperty($field, $found); |
|
| 83 | } |
||
| 84 | |||
| 85 | 7 | if (!property_exists($doc, $field)) { |
|
| 86 | 1 | return false; |
|
| 87 | } |
||
| 88 | |||
| 89 | 6 | $found = true; |
|
| 90 | |||
| 91 | 6 | return $doc->{$field}; |
|
| 92 | } |
||
| 93 | |||
| 94 | 10 | public function matchDocument($doc, $field, $operator, $value) |
|
| 95 | { |
||
| 96 | 10 | $docVal = $this->getFieldValue($doc, $field, $found); |
|
| 97 | |||
| 98 | 10 | if (!$found) { |
|
| 99 | 3 | return false; |
|
| 100 | } |
||
| 101 | |||
| 102 | 9 | switch (true) { |
|
| 103 | 9 | case ($operator === '==' && $docVal == $value): return true; |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 104 | 9 | case ($operator === '===' && $docVal === $value): return true; |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 105 | 9 | case ($operator === '!=' && $docVal != $value): return true; |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 106 | 9 | case ($operator === '!==' && $docVal !== $value): return true; |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 107 | 9 | case ($operator === '>' && $docVal > $value): return true; |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 108 | 9 | case ($operator === '>=' && $docVal >= $value): return true; |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 109 | 9 | case ($operator === '<' && $docVal < $value): return true; |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 110 | 9 | case ($operator === '>=' && $docVal >= $value): return true; |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 111 | 9 | case ($operator === 'IN' && in_array($docVal, (array)$value)): return true; |
|
|
0 ignored issues
–
show
The case body in a switch statement must start on the line following the statement.
According to the PSR-2, the body of a case statement must start on the line immediately following the case statement. switch ($expr) {
case "A":
doSomething(); //right
break;
case "B":
doSomethingElse(); //wrong
break;
} To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
Terminating statement must be on a line by itself
As per the PSR-2 coding standard, the switch ($expr) {
case "A":
doSomething();
break; //wrong
case "B":
doSomething();
break; //right
case "C:":
doSomething();
return true; //right
}
To learn more about the PSR-2 coding standard, please refer to the PHP-Fig. Loading history...
|
|||
| 112 | } |
||
| 113 | |||
| 114 | 9 | return false; |
|
| 115 | } |
||
| 116 | |||
| 117 | 10 | protected function filter($documents, $predicates) |
|
| 118 | { |
||
| 119 | 10 | $result = array(); |
|
| 120 | 10 | $originalDocs = $documents; |
|
| 121 | |||
| 122 | 10 | $andPredicates = array_filter($predicates, function($pred) { |
|
| 123 | 10 | return $pred[0] !== Predicate::LOGICAL_OR; |
|
| 124 | 10 | }); |
|
| 125 | |||
| 126 | 10 | $orPredicates = array_filter($predicates, function($pred) { |
|
| 127 | 10 | return $pred[0] === Predicate::LOGICAL_OR; |
|
| 128 | 10 | }); |
|
| 129 | |||
| 130 | // 5.3 hack for accessing $this inside closure. |
||
| 131 | 10 | $self = $this; |
|
| 132 | |||
| 133 | 10 | foreach($andPredicates as $predicate) { |
|
| 134 | 10 | if (is_array($predicate[1])) { |
|
| 135 | 1 | $documents = $this->filter($documents, $predicate[1]); |
|
| 136 | 1 | } else { |
|
| 137 | 10 | list($type, $field, $operator, $value) = $predicate; |
|
|
0 ignored issues
–
show
The assignment to
$type is unused. Consider omitting it like so list($first,,$third).
This checks looks for assignemnts to variables using the Consider the following code example. <?php
function returnThreeValues() {
return array('a', 'b', 'c');
}
list($a, $b, $c) = returnThreeValues();
print $a . " - " . $c;
Only the variables Instead, the list call could have been. list($a,, $c) = returnThreeValues();
Loading history...
|
|||
| 138 | |||
| 139 | |||
| 140 | $documents = array_values(array_filter($documents, function ($doc) use ($self, $field, $operator, $value) { |
||
| 141 | 10 | return $self->matchDocument($doc, $field, $operator, $value); |
|
| 142 | 10 | })); |
|
| 143 | } |
||
| 144 | |||
| 145 | 10 | $result = $documents; |
|
| 146 | 10 | } |
|
| 147 | |||
| 148 | 10 | foreach($orPredicates as $predicate) { |
|
| 149 | 2 | if (is_array($predicate[1])) { |
|
| 150 | $documents = $this->filter($originalDocs, $predicate[1]); |
||
| 151 | } else { |
||
| 152 | 2 | list($type, $field, $operator, $value) = $predicate; |
|
|
0 ignored issues
–
show
The assignment to
$type is unused. Consider omitting it like so list($first,,$third).
This checks looks for assignemnts to variables using the Consider the following code example. <?php
function returnThreeValues() {
return array('a', 'b', 'c');
}
list($a, $b, $c) = returnThreeValues();
print $a . " - " . $c;
Only the variables Instead, the list call could have been. list($a,, $c) = returnThreeValues();
Loading history...
|
|||
| 153 | |||
| 154 | $documents = array_values(array_filter($originalDocs, function ($doc) use ($self, $field, $operator, $value) { |
||
| 155 | 2 | return $self->matchDocument($doc, $field, $operator, $value); |
|
| 156 | 2 | })); |
|
| 157 | } |
||
| 158 | |||
| 159 | 2 | $result = array_unique(array_merge($result, $documents), SORT_REGULAR); |
|
| 160 | 10 | } |
|
| 161 | |||
| 162 | 10 | return $result; |
|
| 163 | } |
||
| 164 | |||
| 165 | /** |
||
| 166 | * Sorts an array of documents by multiple fields if needed. |
||
| 167 | * |
||
| 168 | * @param array $array An array of Documents. |
||
| 169 | * @param array $args The fields to sort by. |
||
| 170 | * |
||
| 171 | * @return array The sorted array of documents. |
||
| 172 | */ |
||
| 173 | 4 | protected function sort(array $array, array $args) |
|
| 174 | { |
||
| 175 | 4 | $c = count($args); |
|
| 176 | |||
| 177 | // PHP 5.3 hack |
||
| 178 | 4 | $self = $this; |
|
| 179 | |||
| 180 | usort($array, function ($a, $b) use ($self, $args, $c) { |
||
| 181 | 4 | $i = 0; |
|
| 182 | 4 | $cmp = 0; |
|
| 183 | 4 | while ($cmp == 0 && $i < $c) { |
|
| 184 | 4 | $keyName = $args[$i][0]; |
|
| 185 | 4 | if($keyName == 'id' || $keyName == '__id') { |
|
| 186 | 1 | $valueA = $a->getId(); |
|
| 187 | 1 | $valueB = $b->getId(); |
|
| 188 | 1 | } else { |
|
| 189 | 3 | $valueA = $self->getFieldValue($a, $keyName, $found); |
|
| 190 | 3 | if ($found === false) { |
|
| 191 | $valueA = null; |
||
| 192 | } |
||
| 193 | 3 | $valueB = $self->getFieldValue($b, $keyName, $found); |
|
| 194 | 3 | if ($found === false) { |
|
| 195 | $valueB = null; |
||
| 196 | } |
||
| 197 | } |
||
| 198 | |||
| 199 | 4 | if (is_string($valueA)) { |
|
| 200 | 3 | $cmp = strcmp($valueA, $valueB); |
|
| 201 | 4 | } elseif (is_bool($valueA)) { |
|
| 202 | $cmp = $valueA - $valueB; |
||
| 203 | } else { |
||
| 204 | 1 | $cmp = ($valueA == $valueB) ? 0 : (($valueA < $valueB) ? -1 : 1); |
|
| 205 | } |
||
| 206 | |||
| 207 | 4 | if ($args[$i][1] === SORT_DESC) { |
|
| 208 | 4 | $cmp *= -1; |
|
| 209 | 4 | } |
|
| 210 | 4 | $i++; |
|
| 211 | 4 | } |
|
| 212 | |||
| 213 | 4 | return $cmp; |
|
| 214 | 4 | }); |
|
| 215 | |||
| 216 | 4 | return $array; |
|
| 217 | } |
||
| 218 | } |
||
| 219 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.