쿼리 스코프는 자주 쓰는 쿼리 구문을 재사용할 수 있도록 해주는 기능입니다.

 

예로 todo 서비스를 만들 경우 완료 기한이 특정 일(예: 7일) 이내인 할일을 대상으로 where 조건을 추가하여 검색하는 경우가 많을 경우 매번 where 에 완료 기한을 설정하고 뒤에 검색 조건을 추가해야 합니다.

$tasks = \App\Task::where('due_date', '>',\Carbon\Carbon::now()->subDays(7))
                  ->where('name', 'like', '%쇼핑%')->get();
CODE

위의 자주 사용되는 완료 기한 조건을 메소드로 만들어서 재사용할 수 있게 해주는 기능이 쿼리 스코프로 쿼리 코드의 재사용을 높이고 변경되는 쿼리 조건만 추가할 수 있습니다.

 

또 다른 예로 전 절의 소프트 삭제 항목에서 설명한  onlyTrashed(), withTrashed(), trashed() 등의 메소드들이 쿼리 스코프로 작성되어 있습니다.

 

그러면 이제부터 쿼리 스코프를 만드는 방법을 알아 보겠습니다.

쿼리 스코프 정의

모델에 쿼리 스코프를 추가하려면 scope 로 시작하는 메소드를 모델 클래스에 추가해 주면 됩니다.

그러면 Task 모델 클래스에 7일 이내에 완료되어야 할 일을 찾는 쿼리스코프를 작성해 보겠습니다.

app/Task.php

class Task extends Model
{
    protected $fillable = ['name', 'project_id'];
    protected $dates = ['due_date'];

    /**
     * 완료 기한이 7 일 이내인 할 일만 조회.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeDueIn7Days($query)
    {
        return $query->where('due_date', '>', \Carbon\Carbon::now()->subDays(7));
    }
}
PHP

쿼리 스코프를 사용할 경우 scope 접두사를 제외한 나머지 메소드 이름을 앞 자리를 소문자로 해서 호출해 주면 됩니다.

이제 Orm 컨트롤러에 테스트용 메소드를 추가한 후에 브라우저에서 http://homestead.app/orm/due-in7-days 에 연결해 보면 7일 이내의 이슈만 가져 오는 것을 확인할 수 있습니다.

추가로 필요한 쿼리 조건은 메소드 체이닝을 사용하여 쿼리 스코프 뒤에 추가해 주면 됩니다.

public function getDueIn7Days()
{
    $tasks = \App\Task::dueIn7Days()
                ->take(5)
                ->orderBy('due_date', 'desc')                
                ->get();

     return response()->json($tasks,
         200, [], JSON_PRETTY_PRINT);
}
CODE

 

동적 쿼리 스코프

task 를 기한별로 검색하는 경우가 많고 7일 5일 3일등 입력값을 바꿔가며 검색해야 하는 경우 scopeDueIn5Days(), scopeDueIn3Days() 처럼 일일이 쿼리 스코프를 만들어 주는 것은 낭비입니다.

Eloquent 에는 이를 처리하기 위해 파라미터를 넘길 수 있으므로 동적인 쿼리가 가능합니다. 다음은 기한을 입력값으로 받아서 동적으로 쿼리 스코프를 생성하는 메소드입니다.

class Task extends Model
{
    protected $fillable = ['name', 'project_id'];
    protected $dates = ['due_date'];

    /**
     * 완료 기한이 특정일 이내인 할 일만 조회.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeDueInDays($query, $days)
    {
        return $query->where('due_date', '>', \Carbon\Carbon::now()->subDays($days));
    }
}
CODE

 

이제 Orm 컨트롤러에 테스트용 메소드를 추가한 후에 브라우저에서 http://homestead.app/orm/due-in-days/3 에 연결해 보면 3일 이내의 이슈만 가져 오는 것을 확인할 수 있습니다.

public function getDueInDays($day)
{
    $tasks = \App\Task::dueInDays($day)
                ->take(5)
                ->orderBy('due_date', 'desc')                
                ->get();

     return response()->json($tasks,
         200, [], JSON_PRETTY_PRINT);
}
CODE