모델 검색하기(Read)
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);
}
}
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;
}
이제 웹 브라우저로 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;
}
하나의 모델 가져오기
테이블의 모든 모델을 가져오는 것은 메모리와 속도 문제때문에 별로 효용이 없습니다. 기본 키를 사용하여 특정 모델을 가져오는 작업은 find() 메소드를 사용할 수 있으며 파라미터는 찾을 기본 키 값이며 리턴은 컬렉션이 아닌 하나의 모델 객체입니다.
다음은 기본 키 컬럼인 id 값이 5 인 모델을 찾아서 Task Model 클래스를 리턴하는 예제입니다.
public function getFind($id)
{
$task = Task::find($id);
return response()->json($task, 200, [], JSON_PRETTY_PRINT);
}
만약 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);
}
위 코드를 적용하고 브라우저에서 http://homestead.app/orm/find/1234 에 연결하면 id 가 1234인 모델이 없으므로 ModelNotFoundException 예외가 던져져서 아래와 같은 화면이 표시됩니다.
집계(Aggregates) 메소드 사용하기
Eloquent 는 컬렉션과 마찬가지로 count
, max
, min
, sum 같은 집계 함수를 지원하며 추가로 평균값을 구하는 avg() 도 제공하므로
모델의 메소드로 바로 호출하면 됩니다.
$count = Project::count();
$sum = Task::sum('id'); // id 컬럼 값을 합산
$max = Task::max('id'); // 가장 큰 id 컬럼 값을 리턴
$min = Task::min('id'); // 가장 작은 id 컬럼 값을 리턴
다른 메소드처럼 집계 메소드도 메소드 체이닝을 사용하여 where 조건과 같이 사용할 수 있습니다.
$max = Task::where('created_at', '>', \Carbon\Carbon::now()->subDays(7))->max('id');
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);
}
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;
브라우저에서 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);
}
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);
}
메소드 이름을 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"
브라우저로 연결할 때 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);
}
만약 NULL 인 컬럼을 찾을 경우 whereNull() 메소드를, NULL 이 아닌 컬럼을 찾을 경우 whereNotNull() 메소드를 사용할 수 있습니다. 다음은 description 컬럼이 NULL 인 모델을 가져오게 됩니다.
public function getWhereNull()
{
$tasks = Task::whereNull('description')->get();
return response()->json($tasks, 200, [], JSON_PRETTY_PRINT);
}
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);
}
위의 구문은 다음과 같이 SQL 로 변환되며 OrWhere 에서 클로저로 넘긴 조건문은 () 로 그룹핑되는 것을 알수 있습니다.
select * from `tasks` where `id` = '10' or (`name` like 'Ta%' and `id` > '3' and `id` < '7');
그외에 Exist(), NotExist(), Has(), NotHas()등의 메소드와 having, groupBy 등의 메소드가 있으며 더 자세한 내용은 라라벨 한글 매뉴얼이나 영문 매뉴얼(http://laravel.com/docs/5.1/queries#where-clauses)을 참고하면 됩니다.