/** * Parse condition; * * @param $str * @return array * @throws SyntaxErrorException */ private static function parseCondition($str) : array { $parts = []; // REMOVE TRAILING SPACES $str = trim($str); // LOOP THROUGH ALL CHARACTERS $iMax = strlen($str); /** @noinspection ForeachInvariantsInspection */ for ($i = 0; $i < $iMax; $i++) { // IF CHARACTER IS LEFT BRACKET, FIND PAIR BRACKET AND RECURSIVELY FIND CONDITIONS WITHIN THESE BRACKETS if ($str[$i] === '(') { $pairBracketIndex = self::findPairBracketIndex($str, $i + 1); if ($pairBracketIndex > 0) { $part = new WherePart(); $part->type = WherePartType::SUBCONDITION; $subCondition = substr($str, $i + 1, $pairBracketIndex - $i - 1); $part->baseExpr = trim($subCondition); $part->subTree = self::parseCondition($subCondition); $parts[] = $part; $i = $pairBracketIndex; continue; } else { throw new SyntaxErrorException('Missing pair bracket'); } } else { if ($str[$i] === ' ') { if (trim(substr($str, $i, 4)) === Operator::AND) { $part = new WherePart(); $part->type = WherePartType::OPERATOR; $part->value = Operator::AND; $parts[] = $part; $i += 3; } else { if (trim(substr($str, $i, 3)) === Operator::OR) { $part = new WherePart(); $part->type = WherePartType::OPERATOR; $part->value = Operator::OR; $parts[] = $part; $i += 2; } } } else { $match = []; $wasFound = preg_match(self::$regKeyOpValue, substr($str, $i), $match); if ($wasFound) { $part = new WherePart(); $part->type = WherePartType::CONDITION; $part->key = Column::parse($match['key']); $value = $match['value']; if (StringUtils::startsWith($value, '"') && StringUtils::endsWith($value, '"')) { $value = StringUtils::substring($value, 1, StringUtils::length($value) - 1); } $part->value = $value; $part->operator = $match['operator']; $parts[] = $part; $i = $i + strlen($match[0]) - 1; } else { $part = new WherePart(); $part->type = 'UNKNOWN'; $part->value = $str[$i]; $parts[] = $part; $context = self::getErrorContext($str, $i); throw new SyntaxErrorException("Unrecognized char sequence at '{$context['subString']}' starting from index {$context['errorAt']}"); } } } } return $parts; }
/** * @param WherePart[] $conditions * @param string $columnDefaultAlias * @param int $paramCounter * @return array */ private function getParametrizedWhere($conditions, $columnDefaultAlias = '', &$paramCounter = 0) : array { $whereClause = ''; $whereParams = []; foreach ($conditions as $cond) { switch ($cond->type) { case WherePartType::OPERATOR: $whereClause .= ' ' . $cond->value; break; case WherePartType::CONDITION: $whereClause .= ' ' . ($cond->key->getWrappingFunction() === null ? '' : $cond->key->getWrappingFunction() . '(') . (!count($cond->key->getJoinWith()) ? $cond->key->getAlias() ?? $columnDefaultAlias : $cond->key->getJoinWith()[count($cond->key->getJoinWith()) - 1]) . '.' . $cond->key->getName() . ' ' . ($cond->key->getWrappingFunction() === null ? '' : ')') . ($cond->operator === '!=' ? '<>' : $cond->operator) . ' ?' . $paramCounter; if ($cond->operator === Operator::LIKE && !StringUtils::startsWith($cond->value, '%') && !StringUtils::endsWith($cond->value, '%')) { $whereParams[] = '%' . $cond->value . '%'; } else { $whereParams[] = $cond->value; } $paramCounter++; break; case WherePartType::SUBCONDITION: $parametrizedSubWhere = $this->getParametrizedWhere($cond->subTree, $columnDefaultAlias, $paramCounter); $subWhereClause = $parametrizedSubWhere['clause']; $subWhereParams = $parametrizedSubWhere['params']; $whereClause .= ' (' . $subWhereClause . ')'; $whereParams = array_merge($whereParams, $subWhereParams); break; } } return ['clause' => $whereClause, 'params' => $whereParams]; }