diff --git a/src/Illuminate/Contracts/Database/Query/ConditionExpression.php b/src/Illuminate/Contracts/Database/Query/ConditionExpression.php new file mode 100644 index 000000000000..b2e97a6e83c8 --- /dev/null +++ b/src/Illuminate/Contracts/Database/Query/ConditionExpression.php @@ -0,0 +1,7 @@ +wheres[] = compact('type', 'column', 'boolean'); + + return $this; + } + // If the column is an array, we will assume it is an array of key-value pairs // and can add them each as a where clause. We will maintain the boolean we // received when the method was called and pass it into the nested where. @@ -2083,6 +2092,14 @@ public function having($column, $operator = null, $value = null, $boolean = 'and { $type = 'Basic'; + if ($column instanceof ConditionExpression) { + $type = 'Expression'; + + $this->havings[] = compact('type', 'column', 'boolean'); + + return $this; + } + // Here we will make some assumptions about the operator. If only 2 values are // passed to the method, we will assume that the operator is an equals sign // and keep going. Otherwise, we'll require the operator to be passed in. diff --git a/src/Illuminate/Database/Query/Grammars/Grammar.php b/src/Illuminate/Database/Query/Grammars/Grammar.php index fc384662de03..7118fa51878f 100755 --- a/src/Illuminate/Database/Query/Grammars/Grammar.php +++ b/src/Illuminate/Database/Query/Grammars/Grammar.php @@ -706,6 +706,18 @@ public function whereFullText(Builder $query, $where) throw new RuntimeException('This database engine does not support fulltext search operations.'); } + /** + * Compile a clause based on an expression. + * + * @param \Illuminate\Database\Query\Builder $query + * @param array $where + * @return string + */ + public function whereExpression(Builder $query, $where) + { + return $where['column']->getValue($this); + } + /** * Compile the "group by" portions of the query. * @@ -752,6 +764,8 @@ protected function compileHaving(array $having) return $this->compileHavingNotNull($having); } elseif ($having['type'] === 'bit') { return $this->compileHavingBit($having); + } elseif ($having['type'] === 'Expression') { + return $this->compileHavingExpression($having); } elseif ($having['type'] === 'Nested') { return $this->compileNestedHavings($having); } @@ -834,6 +848,17 @@ protected function compileHavingBit($having) return '('.$column.' '.$having['operator'].' '.$parameter.') != 0'; } + /** + * Compile a having clause involving an expression. + * + * @param array $having + * @return string + */ + protected function compileHavingExpression($having) + { + return $having['column']->getValue($this); + } + /** * Compile a nested having clause. * diff --git a/tests/Database/DatabaseQueryBuilderTest.php b/tests/Database/DatabaseQueryBuilderTest.php index b09287792cec..1a785439c044 100755 --- a/tests/Database/DatabaseQueryBuilderTest.php +++ b/tests/Database/DatabaseQueryBuilderTest.php @@ -5,6 +5,7 @@ use BadMethodCallException; use Closure; use DateTime; +use Illuminate\Contracts\Database\Query\ConditionExpression; use Illuminate\Database\ConnectionInterface; use Illuminate\Database\Eloquent\Builder as EloquentBuilder; use Illuminate\Database\Query\Builder; @@ -1833,6 +1834,22 @@ public function testHavingNotNull() $this->assertSame('select "category", count(*) as "total" from "item" where "department" = ? group by "category" having "total" is not null', $builder->toSql()); } + public function testHavingExpression() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('users')->having( + new class() implements ConditionExpression + { + public function getValue(\Illuminate\Database\Grammar $grammar) + { + return '1 = 1'; + } + } + ); + $this->assertSame('select * from "users" having 1 = 1', $builder->toSql()); + $this->assertSame([], $builder->getBindings()); + } + public function testHavingShortcut() { $builder = $this->getBuilder(); @@ -5076,6 +5093,22 @@ public function testCursorPaginateWithUnionWheresMultipleOrders() ]), $result); } + public function testWhereExpression() + { + $builder = $this->getBuilder(); + $builder->select('*')->from('orders')->where( + new class() implements ConditionExpression + { + public function getValue(\Illuminate\Database\Grammar $grammar) + { + return '1 = 1'; + } + } + ); + $this->assertSame('select * from "orders" where 1 = 1', $builder->toSql()); + $this->assertSame([], $builder->getBindings()); + } + public function testWhereRowValues() { $builder = $this->getBuilder();