diff --git a/src/Where.php b/src/Where.php index 1bd5851..4cda175 100644 --- a/src/Where.php +++ b/src/Where.php @@ -15,29 +15,33 @@ public function getWhere() return $this->where; } - public function where($condition, $operator = Sql::ALL) + public function where($condition, ...$args) { + list($condition, $operator) = $this->prepareConditionArguments($condition, $args); $this->mergeCondition($this->where, $this->buildCondition($condition, $operator), Sql::ALL); return $this; } - public function orWhere($condition, $operator = Sql::ALL) + public function orWhere($condition, ...$args) { + list($condition, $operator) = $this->prepareConditionArguments($condition, $args); $this->mergeCondition($this->where, $this->buildCondition($condition, $operator), Sql::ANY); return $this; } - public function notWhere($condition, $operator = Sql::ALL) + public function notWhere($condition, ...$args) { + list($condition, $operator) = $this->prepareConditionArguments($condition, $args); $this->mergeCondition($this->where, $this->buildCondition($condition, $operator), Sql::NOT_ALL); return $this; } - public function orNotWhere($condition, $operator = Sql::ALL) + public function orNotWhere($condition, ...$args) { + list($condition, $operator) = $this->prepareConditionArguments($condition, $args); $this->mergeCondition($this->where, $this->buildCondition($condition, $operator), Sql::NOT_ANY); return $this; @@ -92,6 +96,30 @@ protected function mergeCondition(&$base, array $condition, $operator) } } + /** + * Prepare condition arguments from the different supported where styles + * + * @param mixed $condition + * @param array $args + * + * @return array + */ + protected function prepareConditionArguments($condition, array $args) + { + // Default operator + $operator = Sql::ALL; + + if (! is_array($condition) && ! empty($args)) { + // Variadic + $condition = [(string) $condition => $args]; + } else { + // Array or string format + $operator = array_shift($args) ?: $operator; + } + + return [$condition, $operator]; + } + /** * Clone the properties provided by this trait * diff --git a/src/WhereInterface.php b/src/WhereInterface.php index 2cd1075..8a0a9c4 100644 --- a/src/WhereInterface.php +++ b/src/WhereInterface.php @@ -18,8 +18,8 @@ public function getWhere(); * Add a WHERE part of the query * * This method lets you specify the WHERE part of the query using one of the two following supported formats: - * * String format, e.g. 'id = 1' - * * Array format, e.g. ['id = ?' => 1, ...] + * * String format, e.g. 'id = 1', i.e. `where(string $condition [, mixed ...$args])` + * * Array format, e.g. ['id = ?' => 1, ...], i.e. `where(array $condition [, string $operator])` * * This method does NOT quote the columns you specify for the WHERE. * If you allow user input here, you must protected yourself against SQL injection using @@ -31,12 +31,13 @@ public function getWhere(); * the specified WHERE part using the AND operator. * * @param string|ExpressionInterface|Select|array $condition The WHERE condition - * @param string $operator The operator to combine multiple conditions with, - * if the condition is in the array format + * @param mixed $args If condition is a string, parameter values for placeholders in the condition can be passed. + * If condition is an array, the only argument that is allowed is the operator to use to combine + * these conditions. By default, this operator is {@link Sql::ALL} (AND) * * @return $this */ - public function where($condition, $operator = Sql::ALL); + public function where($condition, ...$args); /** * Add a OR part to the WHERE part of the query @@ -44,12 +45,11 @@ public function where($condition, $operator = Sql::ALL); * Please see {@link where()} for the supported formats and restrictions regarding quoting of the field names. * * @param string|ExpressionInterface|Select|array $condition The WHERE condition - * @param string $operator The operator to combine multiple conditions with, - * if the condition is in the array format + * @param mixed ...$args Please see {@link where()} for details * * @return $this */ - public function orWhere($condition, $operator = Sql::ALL); + public function orWhere($condition, ...$args); /** * Add a AND NOT part to the WHERE part of the query @@ -57,12 +57,11 @@ public function orWhere($condition, $operator = Sql::ALL); * Please see {@link where()} for the supported formats and restrictions regarding quoting of the field names. * * @param string|ExpressionInterface|Select|array $condition The WHERE condition - * @param string $operator The operator to combine multiple conditions with, - * if the condition is in the array format + * @param mixed ...$args Please see {@link where()} for details * * @return $this */ - public function notWhere($condition, $operator = Sql::ALL); + public function notWhere($condition, ...$args); /** * Add a OR NOT part to the WHERE part of the query @@ -70,10 +69,9 @@ public function notWhere($condition, $operator = Sql::ALL); * Please see {@link where()} for the supported formats and restrictions regarding quoting of the field names. * * @param string|ExpressionInterface|Select|array $condition The WHERE condition - * @param string $operator The operator to combine multiple conditions with, - * if the condition is in the array format + * @param mixed ...$args Please see {@link where()} for details * * @return $this */ - public function orNotWhere($condition, $operator = Sql::ALL); + public function orNotWhere($condition, ...$args); } diff --git a/tests/ExpressionThatCanBeRenderedToString.php b/tests/ExpressionThatCanBeRenderedToString.php new file mode 100644 index 0000000..8805be8 --- /dev/null +++ b/tests/ExpressionThatCanBeRenderedToString.php @@ -0,0 +1,18 @@ +expression = $expression; + } + + public function __toString() + { + return $this->expression; + } +} diff --git a/tests/WhereTest.php b/tests/WhereTest.php index 555d2e1..66c723a 100644 --- a/tests/WhereTest.php +++ b/tests/WhereTest.php @@ -62,6 +62,23 @@ public function testSingleNotWhere() $this->assertCorrectStatementAndValues('WHERE NOT (foo = bar)', []); } + public function testVariadicWhereUsedVariadic() + { + $this->query->where('a IN (?) AND b < ?', [1, 2, 3], 4); + $this->assertCorrectStatementAndValues('WHERE a IN (?, ?, ?) AND b < ?', [1, 2, 3, 4]); + } + + public function testNotWhereCombiningVariadicAndArrayStyle() + { + $this->query->where('a = ?', 1); + $this->query->notWhere('a IN (?) AND b < ?', [2, 3, 4], 5); + $this->query->notWhere(['a = ?' => 6, 'b = ?' => 7], Sql::ANY); + $this->assertCorrectStatementAndValues( + 'WHERE ((a = ?) AND (NOT (a IN (?, ?, ?) AND b < ?))) AND (NOT ((a = ?) OR (b = ?)))', + [1, 2, 3, 4, 5, 6, 7] + ); + } + public function testNotWhereArrayFormat() { $this->query->notWhere(['c1 = x']); @@ -209,6 +226,17 @@ public function testWhereWithSelectAndExpression() $this->assertCorrectStatementAndValues('WHERE EXISTS (SELECT 1 FROM t1 WHERE c2 = ? LIMIT 1)', [1]); } + public function testWhereWithExpressionThatCanBeRenderedToString() + { + $this->query->where( + new ExpressionThatCanBeRenderedToString("COALESCE('a', ?) = ?"), + [1, 2], + 1 + ); + + $this->assertCorrectStatementAndValues("WHERE COALESCE('a', ?, ?) = ?", [1, 2, 1]); + } + public function testResetWhere() { $this->query->where('c1 = x');