我正在使用 Laravel 5.6,并尝试使用查询生成器在我的 User
模型中使用计算属性。
用户可以参加类(class),这些类(class)与他们绑定(bind)积分。用户可以通过参加类(class)来获得这些积分。这是一个 BelongsToMany
关系。
我的数据库结构如下所示:
Schema::create('course_attendees', function(Blueprint $table)
{
$table->integer('id', true);
$table->integer('user_id')->index('course_attendees_users_id_fk');
$table->integer('course_id')->index('course_attendees_courses_id_fk');
});
Schema::create('courses', function(Blueprint $table)
{
$table->integer('id', true);
$table->string('title');
$table->string('subject');
$table->string('presenter');
$table->date('start_date')->nullable()->comment('Set to not null later');
$table->date('end_date')->nullable();
$table->decimal('points', 4)->nullable();
$table->string('location');
$table->timestamps();
});
Schema::create('users', function(Blueprint $table)
{
$table->integer('id', true);
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
$table->timestamps();
});
Schema::table('course_attendees', function(Blueprint $table)
{
$table->foreign('course_id', 'course_attendees_courses_id_fk')->references('id')->on('courses')->onUpdate('RESTRICT')->onDelete('RESTRICT');
$table->foreign('user_id', 'course_attendees_users_id_fk')->references('id')->on('users')->onUpdate('RESTRICT')->onDelete('RESTRICT');
});
还可以显示特定时间段内的用户积分。例如当前年份。
我知道我可以使用 mutators 来做到这一点,但这不是我的选择,因为我不能轻易订购它们。
我当前的解决方法是在我的模型上使用本地范围,如下所示:
public function scopeWithPoints(Builder $builder, array $years = [])
{
# Join all columns
$builder->join('user_roles', 'users.role_id', '=', 'user_roles.id')
->leftJoin('course_attendees', 'users.id', '=', 'course_attendees.user_id');
# Join the course table for the years
$builder->leftJoin('courses', function(JoinClause $join) use ($years) {
# Join the courses table with year filters
$join->on('course_attendees.course_id', '=', 'courses.id');
# Apply the filters if available
!empty($years) and $join->whereIn(DB::raw('YEAR(courses.end_date)'), $years);
});
# Select the columns
$builder->select('users.*')->groupBy('users.id');
# Sums
$points = 'SUM(courses.points)';
# Select the points
$builder->selectRaw('COALESCE(' . $points. ', 0) as points');
# Sum up the course points
return $builder;
}
我正在使用这样的代码:
$users = User:all()->withPoints();
$users->paginate();
//...
$test = $users->find(123)->points;
感觉就像我在重复很多代码,因为我的 User
模式中也有这些方法。
/**
* Retrieves the courses which the user has attended
*
* @param array $years
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function attendedCourses(array $years = [])
{
$courses = $this->belongsToMany(Course::class, 'course_attendees');
# Filter the years
if (empty($years)) {
return $courses;
}
return $courses->years($years);
}
/**
* The users course points
*
* @param bool $internal Whether to retrieve internal or external course points
* @param array $years The years to look for attended courses
*
* @return float
*/
public function points(bool $internal, array $years = []) : float
{
# Retrieve the courses
$courses = $this->attendedCourses($years)->external(!$internal);
# Sum points
return $courses->sum('points');
}
可以使用查询生成器以更有效的方式完成此操作吗?
最佳答案
您可以使用withCount()
:
public function scopeWithPoints(Builder $builder, array $years = [])
{
return $builder->withCount([
'attendedCourses as points' => function($query) use($years) {
$query->select(DB::raw('COALESCE(SUM(courses.points), 0)'));
if(!empty($years)) {
$query->whereIn(DB::raw('YEAR(courses.end_date)'), $years);
}
}
]);
}
关于php - 在 Laravel 中通过查询选择计算属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53282341/