From 67b821dde62e64f94aa7d99f1806ecf03ea323e5 Mon Sep 17 00:00:00 2001 From: "Barry vd. Heuvel" Date: Tue, 10 May 2016 09:57:15 +0200 Subject: [PATCH] Rename to withCount, auto column names, default select --- src/Illuminate/Database/Eloquent/Builder.php | 56 ++++++++++++------- .../Database/DatabaseEloquentBuilderTest.php | 25 ++++++--- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/src/Illuminate/Database/Eloquent/Builder.php b/src/Illuminate/Database/Eloquent/Builder.php index 1817ff9ecf58..32fd66e246d5 100755 --- a/src/Illuminate/Database/Eloquent/Builder.php +++ b/src/Illuminate/Database/Eloquent/Builder.php @@ -762,27 +762,6 @@ public function orWhere($column, $operator = null, $value = null) return $this->where($column, $operator, $value, 'or'); } - /** - * Add a relationship count select to the query. - * - * @param string $relation - * @param string $as - * @param \Closure|null $callback - * @return \Illuminate\Database\Eloquent\Builder|static - */ - public function selectCount($relation, $as, Closure $callback = null) - { - $relation = $this->getHasRelationQuery($relation); - - $query = $relation->getRelationCountQuery($relation->getRelated()->newQuery(), $this); - - if ($callback) { - call_user_func($callback, $query); - } - - return $this->selectSub($query->getQuery(), $as); - } - /** * Add a relationship count / exists condition to the query. * @@ -1020,6 +999,41 @@ public function with($relations) return $this; } + /** + * Add subselect queries to count the relations. + * + * @param mixed $relations + * @return $this + */ + public function withCount($relations) + { + // If no columns are set, add the default * columns. + if (is_null($this->query->columns)) { + $this->query->select(['*']); + } + + if (is_string($relations)) { + $relations = func_get_args(); + } + + $relations = $this->parseWithRelations($relations); + + foreach ($relations as $name => $constraints) { + // First determine the count query for the given relationship, + // then run the constraints callback to get the final query. + // This query will be added as subSelect query. + $relation = $this->getHasRelationQuery($name); + $query = $relation->getRelationCountQuery($relation->getRelated()->newQuery(), $this); + + call_user_func($constraints, $query); + + $asColumn = snake_case($name).'_count'; + $this->selectSub($query->getQuery(), $asColumn); + } + + return $this; + } + /** * Parse a list of relations into individuals. * diff --git a/tests/Database/DatabaseEloquentBuilderTest.php b/tests/Database/DatabaseEloquentBuilderTest.php index 4b51d6044d1b..89ba77bc0d76 100755 --- a/tests/Database/DatabaseEloquentBuilderTest.php +++ b/tests/Database/DatabaseEloquentBuilderTest.php @@ -455,25 +455,34 @@ public function testDeleteOverride() $this->assertEquals(['foo' => $builder], $builder->delete()); } - public function testSelectCount() + public function testWithCount() { $model = new EloquentBuilderTestModelParentStub; - $builder = $model->selectCount('foo', 'fooCount'); + $builder = $model->withCount('foo'); - $this->assertEquals('select (select count(*) from "eloquent_builder_test_model_close_related_stubs" where "eloquent_builder_test_model_parent_stubs"."foo_id" = "eloquent_builder_test_model_close_related_stubs"."id") as "fooCount" from "eloquent_builder_test_model_parent_stubs"', $builder->toSql()); + $this->assertEquals('select *, (select count(*) from "eloquent_builder_test_model_close_related_stubs" where "eloquent_builder_test_model_parent_stubs"."foo_id" = "eloquent_builder_test_model_close_related_stubs"."id") as "foo_count" from "eloquent_builder_test_model_parent_stubs"', $builder->toSql()); } - public function testSelectCountWithSelectAndContraintsAndHaving() + public function testWithCountAndSelect() { $model = new EloquentBuilderTestModelParentStub; - $builder = $model->where('bar', 'baz')->select('*'); - $builder->selectCount('foo', 'fooCount', function ($q) { + $builder = $model->select('id')->withCount('foo'); + + $this->assertEquals('select "id", (select count(*) from "eloquent_builder_test_model_close_related_stubs" where "eloquent_builder_test_model_parent_stubs"."foo_id" = "eloquent_builder_test_model_close_related_stubs"."id") as "foo_count" from "eloquent_builder_test_model_parent_stubs"', $builder->toSql()); + } + + public function testWithCountAndContraintsAndHaving() + { + $model = new EloquentBuilderTestModelParentStub; + + $builder = $model->where('bar', 'baz'); + $builder->withCount(['foo' => function ($q) { $q->where('bam', '>', 'qux'); - })->having('fooCount', '>=', 1); + }])->having('fooCount', '>=', 1); - $this->assertEquals('select *, (select count(*) from "eloquent_builder_test_model_close_related_stubs" where "eloquent_builder_test_model_parent_stubs"."foo_id" = "eloquent_builder_test_model_close_related_stubs"."id" and "bam" > ?) as "fooCount" from "eloquent_builder_test_model_parent_stubs" where "bar" = ? having "fooCount" >= ?', $builder->toSql()); + $this->assertEquals('select *, (select count(*) from "eloquent_builder_test_model_close_related_stubs" where "eloquent_builder_test_model_parent_stubs"."foo_id" = "eloquent_builder_test_model_close_related_stubs"."id" and "bam" > ?) as "foo_count" from "eloquent_builder_test_model_parent_stubs" where "bar" = ? having "fooCount" >= ?', $builder->toSql()); $this->assertEquals(['qux', 'baz', 1], $builder->getBindings()); }