From c706a76057f36aaac22c30ed3f4657e593f8ae80 Mon Sep 17 00:00:00 2001 From: "J. King" Date: Fri, 18 Oct 2019 13:10:03 -0400 Subject: [PATCH] Simplify array flattening --- lib/Db/AbstractStatement.php | 45 +++++++++++------------------- lib/Misc/ValueInfo.php | 11 ++++++++ tests/cases/Misc/TestValueInfo.php | 6 ++++ 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/lib/Db/AbstractStatement.php b/lib/Db/AbstractStatement.php index cc8ce42..8471986 100644 --- a/lib/Db/AbstractStatement.php +++ b/lib/Db/AbstractStatement.php @@ -46,23 +46,14 @@ abstract class AbstractStatement implements Statement { return $query; } - public function retypeArray(array $bindings, bool $append = false): bool { - if (!$append) { - $this->types = []; - } - foreach ($bindings as $binding) { - if (is_array($binding)) { - // recursively flatten any arrays, which may be provided for SET or IN() clauses - $this->retypeArray($binding, true); - } else { - $bindId = self::TYPES[trim(strtolower($binding))] ?? 0; - assert($bindId, new Exception("paramTypeInvalid", $binding)); - $this->types[] = $bindId; - } - } - if (!$append) { - $this->prepare(static::mungeQuery($this->query, $this->types)); + public function retypeArray(array $bindings): bool { + $this->types = []; + foreach (ValueInfo::flatten($bindings) as $binding) { // recursively flatten any arrays, which may be provided for SET or IN() clauses + $bindId = self::TYPES[trim(strtolower($binding))] ?? 0; + assert($bindId, new Exception("paramTypeInvalid", $binding)); + $this->types[] = $bindId; } + $this->prepare(static::mungeQuery($this->query, $this->types)); return true; } @@ -79,26 +70,22 @@ abstract class AbstractStatement implements Statement { } } - protected function bindValues(array $values, int $offset = null): int { - $a = (int) $offset; - foreach ($values as $value) { - if (is_array($value)) { - // recursively flatten any arrays, which may be provided for SET or IN() clauses - $a += $this->bindValues($value, $a); - } elseif (array_key_exists($a, $this->types)) { + protected function bindValues(array $values): bool { + // recursively flatten any arrays, which may be provided for SET or IN() clauses + $values = ValueInfo::flatten($values); + foreach ($values as $a => $value) { + if (array_key_exists($a, $this->types)) { $value = $this->cast($value, $this->types[$a]); $this->bindValue($value, $this->types[$a] % self::T_NOT_NULL, ++$a); } else { throw new Exception("paramTypeMissing", $a+1); } } - // once the last value is bound, check that all parameters have been supplied values and bind null for any missing ones + // once all values are bound, check that all parameters have been supplied values and bind null for any missing ones // SQLite will happily substitute null for a missing value, but other engines (viz. PostgreSQL) produce an error - if (is_null($offset)) { - while ($a < sizeof($this->types)) { - $this->bindValue(null, $this->types[$a] % self::T_NOT_NULL, ++$a); - } + for ($a = sizeof($values); $a < sizeof($this->types); $a++) { + $this->bindValue(null, $this->types[$a] % self::T_NOT_NULL, $a + 1); } - return $a - $offset; + return true; } } diff --git a/lib/Misc/ValueInfo.php b/lib/Misc/ValueInfo.php index 752704d..1b3d260 100644 --- a/lib/Misc/ValueInfo.php +++ b/lib/Misc/ValueInfo.php @@ -397,6 +397,17 @@ class ValueInfo { } } + public static function flatten(array $arr): array { + $arr = array_values($arr); + for ($a = 0; $a < sizeof($arr); $a++) { + if (is_array($arr[$a])) { + array_splice($arr, $a, 1, $arr[$a]); + $a--; + } + } + return $arr; + } + public static function int($value): int { $out = 0; if (is_null($value)) { diff --git a/tests/cases/Misc/TestValueInfo.php b/tests/cases/Misc/TestValueInfo.php index 9bf12ba..83053c5 100644 --- a/tests/cases/Misc/TestValueInfo.php +++ b/tests/cases/Misc/TestValueInfo.php @@ -639,4 +639,10 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest { $out->f = $msec; return $out; } + + public function testFlattenArray() { + $arr = [1, [2, 3, [4, 5]], 6, [[7, 8], 9, 10]]; + $exp = range(1,10); + $this->assertSame($exp, I::flatten($arr)); + } }