Unexpected result on relationship filtering using multiple Laravel scopes
up vote
1
down vote
favorite
I'm using Laravel 5.6 and I'm trying to filter a relationship inside my User
model. A user can attend courses, which has points bound to them.
Users can earn these points by attending the courses. This is a BelongsToMany
relationship.
I'm tried creating a scope in this User
model that would only include the attended courses in a range of years.
/**
* Retrieves the courses which the user has attended
*/
public function attendedCourses()
return $this->belongsToMany(Course::class, 'course_attendees');
/**
* Searches the user model
*
* @param IlluminateDatabaseEloquentBuilder $builder
* @param array $years
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeAttendedCoursesInYears(Builder $builder, array $years)
# Filter on the years
$callback = function($q) use ($years)
foreach ($years as $year)
$q->year($year);
;
return $builder->with(['attendedCourses' => $callback]);
In my Course
model, I have a scope that filters on the year that course was in.
public function scopeYear(Builder $query, int $year)
return $query->whereYear('end_date', $year);
With this attendedCoursesInYears
scope I hoped I could then calculate the amount of points for each user by summing up the course points, using other scopes on the Course
model.
public function scopeExternal(Builder $query, bool $flag = true)
$categoryIsExternal = function($query) use ($flag)
$query->external($flag);
;
return $query->whereHas('category', $categoryIsExternal);
In my CourseCategory
modal, the scope looks like this:
/**
* Scope a query to only include external categories.
*
* @param IlluminateDatabaseEloquentBuilder $query
*
* @param bool $flag
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeExternal(Builder $query, $flag = true)
return $query->where('type', '=', $flag ? 'Extern' : 'Intern');
For calculating this, I tried doing something like this.
# Retrieve all the active users
$users = User::all()->attendedCoursesInYears($years);
$test = $users->find(123);
# Calculate the points
$test->attendedCourses()->external(false)->sum('points');
This however returned the total sum of all courses.
I noticed when just calling $test->attendedCourses
it retrieves the filtered collection. The problem with this is that I can't apply the scopes on this.
Questions
- How does it come that it will not sum the filtered collection?
- How can I make it so that it will filter this collection accordingly?
php laravel
|
show 1 more comment
up vote
1
down vote
favorite
I'm using Laravel 5.6 and I'm trying to filter a relationship inside my User
model. A user can attend courses, which has points bound to them.
Users can earn these points by attending the courses. This is a BelongsToMany
relationship.
I'm tried creating a scope in this User
model that would only include the attended courses in a range of years.
/**
* Retrieves the courses which the user has attended
*/
public function attendedCourses()
return $this->belongsToMany(Course::class, 'course_attendees');
/**
* Searches the user model
*
* @param IlluminateDatabaseEloquentBuilder $builder
* @param array $years
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeAttendedCoursesInYears(Builder $builder, array $years)
# Filter on the years
$callback = function($q) use ($years)
foreach ($years as $year)
$q->year($year);
;
return $builder->with(['attendedCourses' => $callback]);
In my Course
model, I have a scope that filters on the year that course was in.
public function scopeYear(Builder $query, int $year)
return $query->whereYear('end_date', $year);
With this attendedCoursesInYears
scope I hoped I could then calculate the amount of points for each user by summing up the course points, using other scopes on the Course
model.
public function scopeExternal(Builder $query, bool $flag = true)
$categoryIsExternal = function($query) use ($flag)
$query->external($flag);
;
return $query->whereHas('category', $categoryIsExternal);
In my CourseCategory
modal, the scope looks like this:
/**
* Scope a query to only include external categories.
*
* @param IlluminateDatabaseEloquentBuilder $query
*
* @param bool $flag
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeExternal(Builder $query, $flag = true)
return $query->where('type', '=', $flag ? 'Extern' : 'Intern');
For calculating this, I tried doing something like this.
# Retrieve all the active users
$users = User::all()->attendedCoursesInYears($years);
$test = $users->find(123);
# Calculate the points
$test->attendedCourses()->external(false)->sum('points');
This however returned the total sum of all courses.
I noticed when just calling $test->attendedCourses
it retrieves the filtered collection. The problem with this is that I can't apply the scopes on this.
Questions
- How does it come that it will not sum the filtered collection?
- How can I make it so that it will filter this collection accordingly?
php laravel
Can you show us the external scope of your Category?
– Chin Leung
yesterday
@ChinLeung Updated my question.
– Bas
yesterday
I just tried to reproduce it locally but I've been getting the correct answer for both external true and false. Try to do the following:$test->attendedCourses()->count()
,$test->attendedCourses()->external(false)->count()
and$test->attendedCourses()->external(true)->count()
, do the numbers add up correctly?
– Chin Leung
yesterday
@ChinLeung Nope. The numbers add up correctly from theexternal
scope. But but the$test->attendedCourses()->count()
returns everything, not using theattendedCoursesInYears
scope for some reason.
– Bas
yesterday
Ah now I understand what you mean... Well your attendedCoursesInYears is filtering the users that has taken a course in the years X-Y, but it's not filtering the courses by the year it's taken. The scope should be done on your pivot table instead.
– Chin Leung
yesterday
|
show 1 more comment
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I'm using Laravel 5.6 and I'm trying to filter a relationship inside my User
model. A user can attend courses, which has points bound to them.
Users can earn these points by attending the courses. This is a BelongsToMany
relationship.
I'm tried creating a scope in this User
model that would only include the attended courses in a range of years.
/**
* Retrieves the courses which the user has attended
*/
public function attendedCourses()
return $this->belongsToMany(Course::class, 'course_attendees');
/**
* Searches the user model
*
* @param IlluminateDatabaseEloquentBuilder $builder
* @param array $years
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeAttendedCoursesInYears(Builder $builder, array $years)
# Filter on the years
$callback = function($q) use ($years)
foreach ($years as $year)
$q->year($year);
;
return $builder->with(['attendedCourses' => $callback]);
In my Course
model, I have a scope that filters on the year that course was in.
public function scopeYear(Builder $query, int $year)
return $query->whereYear('end_date', $year);
With this attendedCoursesInYears
scope I hoped I could then calculate the amount of points for each user by summing up the course points, using other scopes on the Course
model.
public function scopeExternal(Builder $query, bool $flag = true)
$categoryIsExternal = function($query) use ($flag)
$query->external($flag);
;
return $query->whereHas('category', $categoryIsExternal);
In my CourseCategory
modal, the scope looks like this:
/**
* Scope a query to only include external categories.
*
* @param IlluminateDatabaseEloquentBuilder $query
*
* @param bool $flag
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeExternal(Builder $query, $flag = true)
return $query->where('type', '=', $flag ? 'Extern' : 'Intern');
For calculating this, I tried doing something like this.
# Retrieve all the active users
$users = User::all()->attendedCoursesInYears($years);
$test = $users->find(123);
# Calculate the points
$test->attendedCourses()->external(false)->sum('points');
This however returned the total sum of all courses.
I noticed when just calling $test->attendedCourses
it retrieves the filtered collection. The problem with this is that I can't apply the scopes on this.
Questions
- How does it come that it will not sum the filtered collection?
- How can I make it so that it will filter this collection accordingly?
php laravel
I'm using Laravel 5.6 and I'm trying to filter a relationship inside my User
model. A user can attend courses, which has points bound to them.
Users can earn these points by attending the courses. This is a BelongsToMany
relationship.
I'm tried creating a scope in this User
model that would only include the attended courses in a range of years.
/**
* Retrieves the courses which the user has attended
*/
public function attendedCourses()
return $this->belongsToMany(Course::class, 'course_attendees');
/**
* Searches the user model
*
* @param IlluminateDatabaseEloquentBuilder $builder
* @param array $years
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeAttendedCoursesInYears(Builder $builder, array $years)
# Filter on the years
$callback = function($q) use ($years)
foreach ($years as $year)
$q->year($year);
;
return $builder->with(['attendedCourses' => $callback]);
In my Course
model, I have a scope that filters on the year that course was in.
public function scopeYear(Builder $query, int $year)
return $query->whereYear('end_date', $year);
With this attendedCoursesInYears
scope I hoped I could then calculate the amount of points for each user by summing up the course points, using other scopes on the Course
model.
public function scopeExternal(Builder $query, bool $flag = true)
$categoryIsExternal = function($query) use ($flag)
$query->external($flag);
;
return $query->whereHas('category', $categoryIsExternal);
In my CourseCategory
modal, the scope looks like this:
/**
* Scope a query to only include external categories.
*
* @param IlluminateDatabaseEloquentBuilder $query
*
* @param bool $flag
*
* @return IlluminateDatabaseEloquentBuilder
*/
public function scopeExternal(Builder $query, $flag = true)
return $query->where('type', '=', $flag ? 'Extern' : 'Intern');
For calculating this, I tried doing something like this.
# Retrieve all the active users
$users = User::all()->attendedCoursesInYears($years);
$test = $users->find(123);
# Calculate the points
$test->attendedCourses()->external(false)->sum('points');
This however returned the total sum of all courses.
I noticed when just calling $test->attendedCourses
it retrieves the filtered collection. The problem with this is that I can't apply the scopes on this.
Questions
- How does it come that it will not sum the filtered collection?
- How can I make it so that it will filter this collection accordingly?
php laravel
php laravel
edited yesterday
asked yesterday
Bas
1,1021134
1,1021134
Can you show us the external scope of your Category?
– Chin Leung
yesterday
@ChinLeung Updated my question.
– Bas
yesterday
I just tried to reproduce it locally but I've been getting the correct answer for both external true and false. Try to do the following:$test->attendedCourses()->count()
,$test->attendedCourses()->external(false)->count()
and$test->attendedCourses()->external(true)->count()
, do the numbers add up correctly?
– Chin Leung
yesterday
@ChinLeung Nope. The numbers add up correctly from theexternal
scope. But but the$test->attendedCourses()->count()
returns everything, not using theattendedCoursesInYears
scope for some reason.
– Bas
yesterday
Ah now I understand what you mean... Well your attendedCoursesInYears is filtering the users that has taken a course in the years X-Y, but it's not filtering the courses by the year it's taken. The scope should be done on your pivot table instead.
– Chin Leung
yesterday
|
show 1 more comment
Can you show us the external scope of your Category?
– Chin Leung
yesterday
@ChinLeung Updated my question.
– Bas
yesterday
I just tried to reproduce it locally but I've been getting the correct answer for both external true and false. Try to do the following:$test->attendedCourses()->count()
,$test->attendedCourses()->external(false)->count()
and$test->attendedCourses()->external(true)->count()
, do the numbers add up correctly?
– Chin Leung
yesterday
@ChinLeung Nope. The numbers add up correctly from theexternal
scope. But but the$test->attendedCourses()->count()
returns everything, not using theattendedCoursesInYears
scope for some reason.
– Bas
yesterday
Ah now I understand what you mean... Well your attendedCoursesInYears is filtering the users that has taken a course in the years X-Y, but it's not filtering the courses by the year it's taken. The scope should be done on your pivot table instead.
– Chin Leung
yesterday
Can you show us the external scope of your Category?
– Chin Leung
yesterday
Can you show us the external scope of your Category?
– Chin Leung
yesterday
@ChinLeung Updated my question.
– Bas
yesterday
@ChinLeung Updated my question.
– Bas
yesterday
I just tried to reproduce it locally but I've been getting the correct answer for both external true and false. Try to do the following:
$test->attendedCourses()->count()
, $test->attendedCourses()->external(false)->count()
and $test->attendedCourses()->external(true)->count()
, do the numbers add up correctly?– Chin Leung
yesterday
I just tried to reproduce it locally but I've been getting the correct answer for both external true and false. Try to do the following:
$test->attendedCourses()->count()
, $test->attendedCourses()->external(false)->count()
and $test->attendedCourses()->external(true)->count()
, do the numbers add up correctly?– Chin Leung
yesterday
@ChinLeung Nope. The numbers add up correctly from the
external
scope. But but the $test->attendedCourses()->count()
returns everything, not using the attendedCoursesInYears
scope for some reason.– Bas
yesterday
@ChinLeung Nope. The numbers add up correctly from the
external
scope. But but the $test->attendedCourses()->count()
returns everything, not using the attendedCoursesInYears
scope for some reason.– Bas
yesterday
Ah now I understand what you mean... Well your attendedCoursesInYears is filtering the users that has taken a course in the years X-Y, but it's not filtering the courses by the year it's taken. The scope should be done on your pivot table instead.
– Chin Leung
yesterday
Ah now I understand what you mean... Well your attendedCoursesInYears is filtering the users that has taken a course in the years X-Y, but it's not filtering the courses by the year it's taken. The scope should be done on your pivot table instead.
– Chin Leung
yesterday
|
show 1 more comment
1 Answer
1
active
oldest
votes
up vote
1
down vote
The problem is that your scopeAttendedCoursesInYears
method in your User class is to scope out the users who took the courses in the specific years and not scope out the courses that were taken during the years.
To do what you want, you could add a parameter to your relation to filter out the pivot table instead of your users table:
public function attendedCourses(array $years = null)
$query = $this->belongsToMany(Course::class, 'course_user');
if ($years)
$query->whereRaw('YEAR(end_date) IN (?)', [
'years' => implode(',', $years)
]);
return $query;
Then you could achieve your result like this:
$user = User::find(123);
$user->attendedCourses($years)->external(false)->sum('points');
Thanks, but is this the only way? I'd like to have theattendedCourses
filtered before I sum the points. Something like using a scope in my controller. This because I want the fields as columns so I can order and access them easily without too many if statements in a view.
– Bas
yesterday
add a comment |
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
The problem is that your scopeAttendedCoursesInYears
method in your User class is to scope out the users who took the courses in the specific years and not scope out the courses that were taken during the years.
To do what you want, you could add a parameter to your relation to filter out the pivot table instead of your users table:
public function attendedCourses(array $years = null)
$query = $this->belongsToMany(Course::class, 'course_user');
if ($years)
$query->whereRaw('YEAR(end_date) IN (?)', [
'years' => implode(',', $years)
]);
return $query;
Then you could achieve your result like this:
$user = User::find(123);
$user->attendedCourses($years)->external(false)->sum('points');
Thanks, but is this the only way? I'd like to have theattendedCourses
filtered before I sum the points. Something like using a scope in my controller. This because I want the fields as columns so I can order and access them easily without too many if statements in a view.
– Bas
yesterday
add a comment |
up vote
1
down vote
The problem is that your scopeAttendedCoursesInYears
method in your User class is to scope out the users who took the courses in the specific years and not scope out the courses that were taken during the years.
To do what you want, you could add a parameter to your relation to filter out the pivot table instead of your users table:
public function attendedCourses(array $years = null)
$query = $this->belongsToMany(Course::class, 'course_user');
if ($years)
$query->whereRaw('YEAR(end_date) IN (?)', [
'years' => implode(',', $years)
]);
return $query;
Then you could achieve your result like this:
$user = User::find(123);
$user->attendedCourses($years)->external(false)->sum('points');
Thanks, but is this the only way? I'd like to have theattendedCourses
filtered before I sum the points. Something like using a scope in my controller. This because I want the fields as columns so I can order and access them easily without too many if statements in a view.
– Bas
yesterday
add a comment |
up vote
1
down vote
up vote
1
down vote
The problem is that your scopeAttendedCoursesInYears
method in your User class is to scope out the users who took the courses in the specific years and not scope out the courses that were taken during the years.
To do what you want, you could add a parameter to your relation to filter out the pivot table instead of your users table:
public function attendedCourses(array $years = null)
$query = $this->belongsToMany(Course::class, 'course_user');
if ($years)
$query->whereRaw('YEAR(end_date) IN (?)', [
'years' => implode(',', $years)
]);
return $query;
Then you could achieve your result like this:
$user = User::find(123);
$user->attendedCourses($years)->external(false)->sum('points');
The problem is that your scopeAttendedCoursesInYears
method in your User class is to scope out the users who took the courses in the specific years and not scope out the courses that were taken during the years.
To do what you want, you could add a parameter to your relation to filter out the pivot table instead of your users table:
public function attendedCourses(array $years = null)
$query = $this->belongsToMany(Course::class, 'course_user');
if ($years)
$query->whereRaw('YEAR(end_date) IN (?)', [
'years' => implode(',', $years)
]);
return $query;
Then you could achieve your result like this:
$user = User::find(123);
$user->attendedCourses($years)->external(false)->sum('points');
answered yesterday
Chin Leung
6,4532831
6,4532831
Thanks, but is this the only way? I'd like to have theattendedCourses
filtered before I sum the points. Something like using a scope in my controller. This because I want the fields as columns so I can order and access them easily without too many if statements in a view.
– Bas
yesterday
add a comment |
Thanks, but is this the only way? I'd like to have theattendedCourses
filtered before I sum the points. Something like using a scope in my controller. This because I want the fields as columns so I can order and access them easily without too many if statements in a view.
– Bas
yesterday
Thanks, but is this the only way? I'd like to have the
attendedCourses
filtered before I sum the points. Something like using a scope in my controller. This because I want the fields as columns so I can order and access them easily without too many if statements in a view.– Bas
yesterday
Thanks, but is this the only way? I'd like to have the
attendedCourses
filtered before I sum the points. Something like using a scope in my controller. This because I want the fields as columns so I can order and access them easily without too many if statements in a view.– Bas
yesterday
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53224247%2funexpected-result-on-relationship-filtering-using-multiple-laravel-scopes%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Can you show us the external scope of your Category?
– Chin Leung
yesterday
@ChinLeung Updated my question.
– Bas
yesterday
I just tried to reproduce it locally but I've been getting the correct answer for both external true and false. Try to do the following:
$test->attendedCourses()->count()
,$test->attendedCourses()->external(false)->count()
and$test->attendedCourses()->external(true)->count()
, do the numbers add up correctly?– Chin Leung
yesterday
@ChinLeung Nope. The numbers add up correctly from the
external
scope. But but the$test->attendedCourses()->count()
returns everything, not using theattendedCoursesInYears
scope for some reason.– Bas
yesterday
Ah now I understand what you mean... Well your attendedCoursesInYears is filtering the users that has taken a course in the years X-Y, but it's not filtering the courses by the year it's taken. The scope should be done on your pivot table instead.
– Chin Leung
yesterday