Laravel Query Scopes
Global Scopes
Global scopes allow you to add constraints to all queries for a given model. Laravel's own soft delete functionality utilizes global scopes to only retrieve "non-deleted" models from the database. Writing your own global scopes can provide a convenient, easy way to make sure every query for a given model receives certain constraints.
To assign a global scope to a model, you should override the model's booted method and invoke the model's addGlobalScope method. The addGlobalScope method accepts an instance of your scope as its only argument:
#Apply with Anonymous Global Scopes
/**
* * The "booted" method of the model.
*
* @return void
*/
protected static function booted()
{
static::addGlobalScope('withoutGeneralTest', function (Builder $query) {
$query->where([
['lession_id', '=', null],
['topic_id', '=', null],
]);
});
static::addGlobalScope('activeTest', function (Builder $query) {
$query->where('test_status', self::TEST_ACTIVE);
});
}
#Removing Global Scopes
/**
* * show.
*
* @param mixed $test
* @return void
*/
public function show(Test $test, $request)
{
$test->withoutGlobalScope('withoutGeneralTest');
$test->loadMissing(['questions'=>function ($q) {
$q->cacheFor(70)->select('test_id', 'quest_id', 'quest_name', 'quest_status', 'quest_content', 'quest_type', 'quest_level', 'quest_parent', 'quest_priority', 'questkind_id', 'quest_intro', 'quest_content');
},
'questions.questAnswers'=>function ($q) {
$q->cacheFor(70);
},
'questions.questExplains'=>function ($q) {
$q->cacheFor(70);
},
'memberHistories'=>function ($q) {
$q->select('test_history_id', 'test_history_date', 'test_history_numanswer', 'test_history_numwrite', 'test_history_numskip', 'test_history_numcorrect', 'test_history_point', 'test_history_isfinish', 'test_total_time', 'test_id')
->byMember($this->member)
->orderLatest();
},
'favorites'=>function ($q) {
$q->byMember($this->member);
},
]);
return $test;
}
Local Scopes
Local scopes allow you to define common sets of query constraints that you may easily re-use throughout your application. For example, you may need to frequently retrieve all users that are considered "popular". To define a scope, prefix an Eloquent model method with scope. Scopes should always return a query builder instance:
/**
* * scopeByMember.
*
* @param mixed $query
* @param mixed $member
* @return void
*/
public function scopeByMember($query, Member $member)
{
return $query->where('member_id', $member->member_id);
}
/**
* * latest.
*
* @param mixed $query
* @return void
*/
public function scopeOrderLatest($query)
{
return $query->orderBy('test_history_id', 'desc');
}
#Utilizing A Local Scope
Once the scope has been defined, you may call the scope methods when querying the model. However, you should not include the scope prefix when calling the method. You can even chain calls to various scopes:
/**
* * getMemberTestHistory.
*
* @param mixed $test
* @return void
*/
public function getMemberTestHistory(Test $test)
{
$selects = ['test_history_id', 'test_history_date', 'test_history_numanswer', 'test_history_numwrite', 'test_history_numskip', 'test_history_numcorrect', 'test_history_point', 'test_history_isfinish', 'test_total_time', 'test_id'];
if (! $test->relationLoaded('memberHistories')) {
return $test->memberHistories()
->select($selects)
->byMember($this->member)
->orderLatest()
->first();
}
return $test->memberHistories->first();
}