Last active
September 23, 2021 09:00
-
-
Save vluzrmos/70d32ddd2569cdc561efd4df43d3abbe to your computer and use it in GitHub Desktop.
Laravel 5.1 withCount(relation) method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App; | |
use Illuminate\Database\Eloquent\Builder as EloquentBuilder; | |
use Illuminate\Database\Eloquent\Relations\HasMany; | |
use Illuminate\Database\Eloquent\Relations\HasOneOrMany; | |
use Illuminate\Database\Eloquent\Relations\Relation; | |
use Illuminate\Database\Query\Builder as QueryBuilder; | |
use Illuminate\Database\Query\Expression; | |
trait HasWithCountScope | |
{ | |
/** | |
* @param QueryBuilder|EloquentBuilder $query | |
* @param string|array $name | |
*/ | |
public function scopeWithCount($query, $name) | |
{ | |
$relations = is_array($name) ? $name : array_slice(func_get_args(), 1); | |
if (empty($query->columns)) { | |
$query->select(['*']); | |
} | |
foreach ($relations as $key => $constraint) { | |
list($name, $alias, $constraint) = $this->parseWithCountConstraint($key, $constraint); | |
$query->selectSub($this->getRelatedCountSubQuery($name, $constraint), $alias); | |
} | |
} | |
/** | |
* @param string $name | |
* @param \Closure|null $constraint | |
* @return \Illuminate\Database\Query\Builder | |
*/ | |
public function getRelatedCountSubQuery($name, $constraint = null) | |
{ | |
/** @var Relation|HasOneOrMany|HasMany $relation */ | |
$relation = call_user_func([$this, $name]); | |
$related = $relation->getRelated(); | |
$relatedKey = $relation->getForeignKey(); | |
$key = $relation->getQualifiedParentKeyName(); | |
/** @var QueryBuilder|EloquentBuilder $subQuery */ | |
$subQuery = $related->newQuery(); | |
$subQuery->select(new Expression('COUNT(*)')); | |
$subQuery->whereRaw("{$relatedKey} = {$key}"); | |
if ($constraint) { | |
$subQuery->where($constraint); | |
} | |
if ($subQuery instanceof EloquentBuilder) { | |
return $subQuery->getQuery(); | |
} | |
return $subQuery; | |
} | |
/** | |
* @param string $key | |
* @param string|\Closure $constraint | |
* @return array | |
*/ | |
protected function parseWithCountConstraint($key, $constraint = null) | |
{ | |
list($name, $constraint) = is_string($key) ? [$key, $constraint] : [$constraint, null]; | |
list($name, $alias) = $this->parseWithCountAlias($name); | |
return [$name, $alias, $constraint]; | |
} | |
/** | |
* @param $name | |
* @return array | |
*/ | |
protected function parseWithCountAlias($name) | |
{ | |
$names = preg_split('/\s+(as)\s+/i', $name); | |
if (count($names) > 1) { | |
$name = $names[0]; | |
$alias = $names[1]; | |
} else { | |
$alias = $name.'_count'; | |
} | |
return [$name, $alias]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App; | |
use \Illuminate\Database\Eloquent\Model; | |
class Post extends Model{ | |
use HasWithCountScope; | |
public function comments() { | |
return $this->hasMany(Comment::class); | |
} | |
public function votes() { | |
return $this->hasMany(Vote::class); | |
} | |
} | |
// USAGE 1 | |
$posts = Post::withCount('comments')->get(); | |
$posts[0]->comments_count; //total comments of the post | |
// USAGE 2 | |
$posts = Post::withCount(['votes', 'comments' => function ($query) { | |
$query->where('created_at', '>', date('yesterday')) | |
}])->get(); | |
$posts[0]->comments_count; //total comments created after yesterday | |
$posts[0]->votes_count; //total votes of the posts | |
// USAGE 3 | |
$posts = Post::withCount(['votes as total_votes', 'comments as total_comments' => function ($query) { | |
$query->where('created_at', '>', date('yesterday')) | |
}])->get(); | |
$posts[0]->total_comments; //total comments created after yesterday | |
$posts[0]->total_votes; //total votes of the posts |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Seems like it won't work with polymorphic relationships. So made some changes to make it work for polymorhpic relationship. Thank you for this gist @vluzrmos.