/** * @param string|array $filter Filter for querying records by * @param array $params Filter replacement parameters * * @return array * @throws \DreamFactory\Core\Exceptions\BadRequestException */ protected static function buildFilterArray($filter, $params = null) { if (empty($filter)) { return []; } if (is_array($filter)) { // assume client knows correct usage of Mongo query language return static::toMongoObjects($filter); } // handle logical operators first $logicalOperators = DbLogicalOperators::getDefinedConstants(); foreach ($logicalOperators as $logicalOp) { if (DbLogicalOperators::NOT_STR === $logicalOp) { // NOT(a = 1) or NOT (a = 1)format if (0 === stripos($filter, $logicalOp . '(') || 0 === stripos($filter, $logicalOp . '(')) { $parts = trim(substr($filter, 3)); $parts = static::buildFilterArray($parts, $params); return [static::localizeOperator($logicalOp) => $parts]; } } else { // (a = 1) AND (b = 2) format $paddedOp = ') ' . $logicalOp . ' ('; if (false !== ($pos = stripos($filter, $paddedOp))) { $left = trim(substr($filter, 0, $pos)); $right = trim(substr($filter, $pos + strlen($paddedOp))); $left = static::buildFilterArray($left, $params); $right = static::buildFilterArray($right, $params); return [static::localizeOperator($logicalOp) => [$left, $right]]; } // (a = 1)AND(b = 2) format $paddedOp = ')' . $logicalOp . '('; if (false !== ($pos = stripos($filter, $paddedOp))) { $left = trim(substr($filter, 0, $pos)); $right = trim(substr($filter, $pos + strlen($paddedOp))); $left = static::buildFilterArray($left, $params); $right = static::buildFilterArray($right, $params); return [static::localizeOperator($logicalOp) => [$left, $right]]; } } } $filter = trim(trim($filter, '()')); // the rest should be comparison operators // Note: order matters here! $sqlOperators = DbComparisonOperators::getParsingOrder(); foreach ($sqlOperators as $sqlOp) { $paddedOp = static::padOperator($sqlOp); if (false !== ($pos = stripos($filter, $paddedOp))) { $field = trim(substr($filter, 0, $pos)); $negate = false; if (false !== strpos($field, ' ')) { $parts = explode(' ', $field); if (count($parts) > 2 || 0 !== strcasecmp($parts[1], trim(DbLogicalOperators::NOT_STR))) { // invalid field side of operator throw new BadRequestException('Invalid or unparsable field in filter request.'); } $field = $parts[0]; $negate = true; } $value = trim(substr($filter, $pos + strlen($paddedOp))); if (DbComparisonOperators::requiresValueList($sqlOp)) { $value = trim($value, '()[]'); $parsed = []; foreach (explode(',', $value) as $each) { $parsed[] = static::determineValue($each, $field, $params); } $value = $parsed; } elseif (DbComparisonOperators::requiresNoValue($sqlOp)) { switch ($sqlOp) { case DbComparisonOperators::IS_NULL: return [$field => null]; case DbComparisonOperators::IS_NOT_NULL: return [$field => ['$ne' => null]]; case DbComparisonOperators::DOES_EXIST: return [$field => ['$exists' => true]]; case DbComparisonOperators::DOES_NOT_EXIST: return [$field => ['$exists' => false]]; } } else { $value = static::determineValue($value, $field, $params); if ('$eq' === static::localizeOperator($sqlOp)) { // prior to 3.0 if ($negate) { return [$field => ['$ne' => $value]]; } return [$field => $value]; } elseif (DbComparisonOperators::LIKE === $sqlOp) { // WHERE name LIKE "%Joe%" (array("name" => new MongoRegex("/Joe/"))); // WHERE name LIKE "Joe%" (array("name" => new MongoRegex("/^Joe/"))); // WHERE name LIKE "%Joe" (array("name" => new MongoRegex("/Joe$/"))); if ('%' == $value[strlen($value) - 1]) { if ('%' == $value[0]) { $value = '/' . trim($value, '%') . '/ '; } else { $value = '/^' . rtrim($value, '%') . '/ '; } } else { if ('%' == $value[0]) { $value = '/' . trim($value, '%') . '$/ '; } else { $value = '/' . $value . '/ '; } } return [$field => new \MongoRegex($value)]; } } if ($negate) { $value = ['$not' => $value]; } return [$field => [static::localizeOperator($sqlOp) => $value]]; } } return $filter; }