$value) { if ($key === $index) { $index++; if ($sql && !str::ends_with(" ", $sql) && !str::starts_with(" ", $value)) { $sql .= " "; } $sql .= $value; } } return $sql; } protected static function is_sep(&$cond): bool { if (!is_string($cond)) return false; if (!preg_match('/^\s*(and|or|not)\s*$/i', $cond, $ms)) return false; $cond = $ms[1]; return true; } static function parse_conds(?array $conds, ?array &$sql, ?array &$bindings): void { if (!$conds) return; $sep = null; $index = 0; $condsql = []; foreach ($conds as $key => $cond) { if ($key === $index) { ## séquentiel if ($index === 0 && self::is_sep($cond)) { $sep = $cond; } elseif (is_bool($cond)) { # ignorer les valeurs true et false } elseif (is_array($cond)) { # condition récursive self::parse_conds($cond, $condsql, $bindings); } else { # condition litérale $condsql[] = strval($cond); } $index++; } elseif ($cond === false) { ## associatif # condition litérale ignorée car condition false } elseif ($cond === true) { # condition litérale sélectionnée car condition true $condsql[] = strval($key); } else { ## associatif # paramètre $i = false; if ($bindings !== null && array_key_exists($key, $bindings)) { $i = 2; while (array_key_exists("$key$i", $bindings)) { $i++; } } # value ou [operator, value] $condprefix = $condsep = $condsuffix = null; if (is_array($cond)) { $condkey = 0; $condkeys = array_keys($cond); $op = null; if (array_key_exists("op", $cond)) { $op = $cond["op"]; } elseif (array_key_exists($condkey, $condkeys)) { $op = $cond[$condkeys[$condkey]]; $condkey++; } $op = strtolower($op); $condvalues = null; switch ($op) { case "between": # ["between", $upper, $lower] $condsep = " and "; if (array_key_exists("lower", $cond)) { $condvalues[] = $cond["lower"]; } elseif (array_key_exists($condkey, $condkeys)) { $condvalues[] = $cond[$condkeys[$condkey]]; $condkey++; } if (array_key_exists("upper", $cond)) { $condvalues[] = $cond["upper"]; } elseif (array_key_exists($condkey, $condkeys)) { $condvalues[] = $cond[$condkeys[$condkey]]; $condkey++; } break; case "in": # ["in", $values] $condprefix = "("; $condsep = ", "; $condsuffix = ")"; $condvalues = null; if (array_key_exists("values", $cond)) { $condvalues = cl::with($cond["values"]); } elseif (array_key_exists($condkey, $condkeys)) { $condvalues = cl::with($cond[$condkeys[$condkey]]); $condkey++; } break; case "null": case "is null": $op = "is null"; break; case "not null": case "is not null": $op = "is not null"; break; default: if (array_key_exists("value", $cond)) { $condvalues = [$cond["value"]]; } elseif (array_key_exists($condkey, $condkeys)) { $condvalues = [$cond[$condkeys[$condkey]]]; $condkey++; } } } elseif ($cond !== null) { $op = "="; $condvalues = [$cond]; } else { $op = "is null"; $condvalues = null; } $cond = [$key, $op]; if ($condvalues !== null) { $parts = []; foreach ($condvalues as $condvalue) { if (is_array($condvalue)) { $first = true; foreach ($condvalue as $value) { if ($first) { $first = false; } else { if ($sep === null) $sep = "and"; $parts[] = " $sep "; $parts[] = $key; $parts[] = " $op "; } $param = "$key$i"; $parts[] = ":$param"; $bindings[$param] = $value; if ($i === false) $i = 2; else $i++; } } else { $param = "$key$i"; $parts[] = ":$param"; $bindings[$param] = $condvalue; if ($i === false) $i = 2; else $i++; } } $cond[] = $condprefix.implode($condsep, $parts).$condsuffix; } $condsql[] = implode(" ", $cond); } } if ($sep === null) $sep = "and"; $count = count($condsql); if ($count > 1) { $sql[] = "(" . implode(" $sep ", $condsql) . ")"; } elseif ($count == 1) { $sql[] = $condsql[0]; } } static function parse_set_values(?array $values, ?array &$sql, ?array &$bindings): void { if (!$values) return; $index = 0; $parts = []; foreach ($values as $key => $part) { if ($key === $index) { ## séquentiel if (is_array($part)) { # paramètres récursifs self::parse_set_values($part, $parts, $bindings); } else { # paramètre litéral $parts[] = strval($part); } $index++; } else { ## associatif # paramètre $param = $key; if ($bindings !== null && array_key_exists($param, $bindings)) { $i = 2; while (array_key_exists("$key$i", $bindings)) { $i++; } $param = "$key$i"; } # value $value = $part; $part = [$key, "="]; if ($value === null) { $part[] = "null"; } else { $part[] = ":$param"; $bindings[$param] = $value; } $parts[] = implode(" ", $part); } } $sql = cl::merge($sql, $parts); } protected static function check_eof(string $tmpsql, string $usersql): void { self::consume(';\s*', $tmpsql); if ($tmpsql) { throw new ValueException("unexpected value at end: $usersql"); } } abstract protected static function verifix(&$sql, ?array &$bindinds=null, ?array &$meta=null): void; function __construct($sql, ?array $bindings=null) { static::verifix($sql, $bindings, $meta); $this->sql = $sql; $this->bindings = $bindings; $this->meta = $meta; } /** @var string */ protected $sql; /** @var ?array */ protected $bindings; /** @var ?array */ protected $meta; }