Eloquent 에서 SELECT 의 결과로 Multi result-set 을 리턴하는 경우 전 절에서 설명한 컬렉션(Illuminate\Support\Collection)을 상속받은 Illuminate\Database\Eloquent\Collection를 리턴하므로 DBMS 의 레코드를 컬렉션처럼 다룰 수 있습니다.

모든 데이타 읽기

먼저 모델 데이타를 가져올 경우 컬렉션의 all() 메소드를 사용하면 테이블의 모든 데이타를 가져올 수 있습니다. 

컨트롤러는  App\Http\Controllers 네임스페이스를 가지므로 최상단에 use App\Task; 과 같이 사용하는 모델을 선언하는 구문을 포함 시켜야 정상 동작하며 향후 예제부터는 use 키워드는 생략하겠습니다.

use App\Task;
use App\Project;

class OrmController extends Controller
{
    public function getAll()
    {
    	$tasks = Task::all();
 
		return response()->json($tasks, 200, [], JSON_PRETTY_PRINT);
    }
}
CODE

Task::all(); 에 의해 모든 모델을 가져오므로 전 절에서 생성한 모든 모델 데이타 Task 모델과 배열로 변환되어 $tasks 변수에 담기게 됩니다.

 

reponses() 헬퍼의 json() 메소드는 파라미터로 입력된 객체를 JSON 으로 변환하고 HTTP 헤더에 Content-Type: application/json 를 자동으로 추가해 주며 보기 좋게 표시하려고 JSON_PRETTY_PRINT 옵션으로 json 결과를 포맷팅했습니다.

라라벨은 명시적으로 json() 메소드를 호출하여 변환하지 않아도 Response 의 리턴되는 객체가 Eloquent Model 을 상속받은 객체이거나 배열이면 자동으로 JSON 형식으로 변환해 주므로 아래도 자동으로 결과를 json 으로 변환해 줍니다.

public function getAll()   
{
	$tasks = Task::all(); 
	return $tasks;
} 
CODE

 

이제 웹 브라우저로 http://homestead.app/orm/all 에 연결해 보면 다음과 같이 JSON 형식의 결과값을 확인할 수 있습니다.

Task.php에는 테이블의 컬럼명과 매핑되는 변수가 하나도 기술되어 있지 않았지만 리턴된 Task 모델을 보면 id, project_id, name 등 테이블의 컬럼값이 저장되어 있습니다.

이처럼 Eloquent 는 테이블의 컬럼을 모델 클래스의 프로퍼티로 자동으로 바인딩을 해주며 이는 PHP의 오버로딩(REF: 동적 프로퍼티/메소드 생성) 기능을 사용하여  이루어 집니다.

 

가져온 컬럼값을 사용하려면 다음과 같이 property 에 접근할 때 사용하는 연산자인 -> 를 사용하면 됩니다.

foreach ($tasks as $task)
{
	echo "Id: " . $task->id . " name :" . $task->name;
}
CODE

 

하나의 모델 가져오기

테이블의 모든 모델을 가져오는 것은 메모리와 속도 문제때문에 별로 효용이 없습니다. 기본 키를 사용하여 특정 모델을 가져오는 작업은 find() 메소드를 사용할 수 있으며 파라미터는 찾을 기본 키 값이며 리턴은 컬렉션이 아닌 하나의 모델 객체입니다.

다음은 기본 키 컬럼인 id 값이 5 인 모델을 찾아서 Task Model 클래스를 리턴하는 예제입니다.

public function getFind($id)
{
    $task = Task::find($id);

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

 

만약 id 에 해당하는 모델이 없을 경우 find() 메소드를 null 을 리턴하므로 $task 변수는 null 이 들어가며 이를 JSON 으로 변환하면 '{}' 이 출력됩니다. 

브라우저로 http://homestead.app/orm/find/1234 연결해 보면 아래와 같이 빈 JSON 결과를 볼 수 있습니다.

 

모델이 없을 경우 null 대신 ModelNotFoundException 예외를 받기를 원할 경우 findOrFail() 메소드를 사용하면 됩니다.

public function getFind($id = 2)
{
    $task = Task::findOrFail($id);

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

위 코드를 적용하고 브라우저에서 http://homestead.app/orm/find/1234 에  연결하면 id 가 1234인 모델이 없으므로 ModelNotFoundException  예외가 던져져서 아래와 같은 화면이 표시됩니다.

집계(Aggregates) 메소드 사용하기

Eloquent 는 컬렉션과 마찬가지로 countmaxminsum 같은 집계 함수를 지원하며 추가로 평균값을 구하는 avg() 도 제공하므로 모델의 메소드로 바로 호출하면 됩니다.

$count = Project::count();
$sum = Task::sum('id'); // id 컬럼 값을 합산
$max = Task::max('id'); // 가장 큰 id 컬럼 값을 리턴
$min = Task::min('id'); // 가장 작은 id 컬럼 값을 리턴
CODE

 다른 메소드처럼 집계 메소드도 메소드 체이닝을 사용하여 where 조건과 같이 사용할 수 있습니다.

$max = Task::where('created_at', '>', \Carbon\Carbon::now()->subDays(7))->max('id');
CODE

 

Where 사용하기

기본 키 컬럼 값이 아닌 다른 조건을 사용하여 데이타를 조회해야 할 경우 where() 메소드를 사용하면 되며 여러 개의 조건을 사용할 경우 메소드 체이닝을 사용하여 -> 연산자로 조건을 연이어서 넣어주면 됩니다.

public function getWhere()
{
	$tasks = Task::where('id', '>', 10)
				->where('id', '<', 20)
				->where('name', 'like', 'Ta%')
				->orderBy('name', 'desc')
				->skip(5)
				->take(3)
				->get();
 
    return  response()->json($tasks);
}
CODE

 SQL 을 아는 독자라면 별도의 설명이 필요 없을 정도로 소스가 간결하지만 각 메소드의 의미에 대해서 간략하게 설명하겠습니다.

  • where('id', '>', 10) : id 가 10보다 큰 모델을 찾습니다.

  • where('id', '<', 20) : id 가 20보다 작은 모델을 찾습니다. where 는 기본적으로  AND 이므로 10보다 크고 20보다 작은 모델이 검색 대상이 됩니다.

  • where('name', 'like', 'Ta%') : LIKE 구문을 사용한 where 조건문으로 name 컬럼이 Ta로 시작하는 컬럼을 찾으며 모든 Task 모델의 name 컬럼은 Task 로 시작하므로 위의 조건에서 바로 위의 id 조건으로 검색된 모든 모델이 해당됩니다.

  • orderBy(name', 'desc') : name 컬럼을 기반으로 내림차순으로 정렬합니다.

  • skip(5) : 최종 결과에서 5개의 모델을 건너 뛰고 그 이후의 모델을 가져오며 SQL의 OFFSET 구문과 동일한 의미입니다.

  • take(3) : 최종 결과에서 총 3 개의 모델만 가져오며 SQL 의 LIMIT 구문과 동일한 의미입니다.

  • get() : get() 메소드를 호출해야 최종 모델을 가져오게 되며 만약 get() 을 누락하면  쿼리 결과가 아닌 쿼리를 만드는 클래스인 Illuminate\Database\Eloquent\Builder 가 리턴됩니다.

where 조건에 '>' 나 '=', '<' 같은 비교 연산자를 사용할 경우 앞 뒤에 공백이 있으면 제대로 동작하지 않습니다. 즉 where('id', ' >', 10) 와 같이 공백이 있는 다음과 같은 PDO exception 을 발생시키게 되니 주의하여야 합니다.

PHP error:  PDO::prepare(): send of 83 bytes failed with errno=32 Broken pipe

 

최종 검색 조건은 아래와 같은 SQL 로 변환되어 id가 10보다 크고 20보다 작은 모델을 name 컬럼을 기준으로 내림차순으로 정렬한 후에 5개의 모델을 건너뛰고 이후 3개의 모델을 가져오게 되며 

select * from `tasks` where `id` > '10' and `id` < '20' order by `name` desc limit 3 offset 5;
CODE

 

브라우저에서 http://homestead.app/orm/where 에  연결하면 검색된 모델의 결과를 볼수 있습니다.

첫 번째 모델만 가져올 경우 get() 대신 first() 메소드를 사용할 수 있으며 위의 예제를 수정하여 get()first() 로 변경한 후에 결과를 보면 예상대로 id 가 16인 모델이 출력됩니다.

In, Between, Null 연산자

where 문에 여러 가지 조건문을 같이 사용할 경우 where + 조건문 이름의 메소드를 사용하면 되며 예로 in 으로 여러 개의 모델을 찾을 경우 whereIn 메소드를 사용하면 됩니다.

다음은 id 가  3, 5, 6인 모델을 찾아서 리턴합니다.

public function getWhereIn()
{
   $tasks = Task::whereIn('id', [3, 5, 6])->get();
 
   return response()->json($tasks, 200, [], JSON_PRETTY_PRINT);
}
CODE

whereIn 과 대비되는 메소드로는 whereNotIn 이 있으며 다음 예제는 id 가 3,5,6 이 아닌 모델을 찾게 됩니다.

public function getWhereNotIn()
{
   $tasks = Task::whereNotIn ('id', [3, 5, 6])->get();
 
   return response()->json($tasks, 200, [], JSON_PRETTY_PRINT);
}
CODE

 

메소드 이름을 URL 로 변환하려면 HTTP 메소드 이름(get) 을 뺀 나머지 이름을 snake_case()str_slug() 함수를 이용하여 변환해야 합니다. 간단하게 테스트 하여 결과를 얻기 위해 tinker 에서 헬퍼 함수를 실행해 봅시다.

$ php artisan tinker
 
>>> str_slug(snake_case('WhereIn'))
=> "where-in"
>>> str_slug(snake_case('WhereNotIn'))
=> "where-not-in"
CODE

브라우저로 연결할 때 URL 은 where-in 이므로 http://homestead.app/orm/where-in 에 연결하여 결과를 확인해 봅시다.

 

whereIn 에 넘기는 배열은 SQL 로 변환되므로 마지막 요소 뒤에 , 가 있으면 에러가 발생합니다.

 

구간 검색을 할 경우 whereBetween() 메소드를 사용하여 구간 검색을 할 수 있습니다.  두 번째 파라미터에 구간 값을 넣어주면 되며 대비되는 메소드로 whereNotBetween() 이 있습니다.

다음은 id 가 5 에서 9 인 task 를 찾는 구간 검색 쿼리입니다.

public function getWhereBetween()
{
   $tasks = Task::whereBetween('id', [5, 9])->get();
 
   return response()->json($tasks, 200, [], JSON_PRETTY_PRINT);
}
CODE

 

만약 NULL 인 컬럼을 찾을 경우 whereNull() 메소드를,  NULL 이 아닌 컬럼을 찾을 경우 whereNotNull() 메소드를 사용할 수 있습니다. 다음은 description 컬럼이 NULL 인 모델을 가져오게 됩니다.

public function getWhereNull()
{
   $tasks = Task::whereNull('description')->get();
 
   return response()->json($tasks, 200, [], JSON_PRETTY_PRINT);
}
CODE

 

Where 파라미터 그룹핑

where 구문이 복잡하거나 또는 where 조건에 붙는 파라미터를 그룹핑해야 할 경우 클로저를 사용할 수 있습니다.

클로저의 파라미터는 SQL 객체이므로 메소드 체이닝을 사용하여 그룹핑할 where 조건을 적어주면 됩니다. 다음은 (id 가 10) 또는 (name이 Ta 로 시작하고 id 가 3보다 크고 7보다 작은) 모델을 가져오기 위해 클로저로 파라미터를 그룹핑한 예제입니다.

public function getWhereParam()
{
    $tasks = Task::where('id', '=', 10)
            ->OrWhere(function ($query) {
                $query->where('name', 'like', 'Ta%')
                  ->where('id', '>', 3)
                  ->where('id', '<', 7);
            })
            ->get();

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

위의 구문은 다음과 같이 SQL 로 변환되며 OrWhere 에서 클로저로 넘긴 조건문은 () 로 그룹핑되는 것을 알수 있습니다.

select * from `tasks` where `id` = '10' or (`name` like 'Ta%' and `id` > '3' and `id` < '7');
CODE

 

그외에 Exist(), NotExist(), Has(), NotHas()등의 메소드와 having, groupBy 등의 메소드가 있으며 더 자세한 내용은 라라벨 한글 매뉴얼이나 영문 매뉴얼(http://laravel.com/docs/5.1/queries#where-clauses)을 참고하면 됩니다.