컨트롤러란
라우트 파일에 모든 요청 처리 로직을 클로저로 정의하는 대신, “컨트롤러” 클래스를 사용해 이 동작을 정리할 수 있습니다.
컨트롤러는 관련된 요청 처리 로직을 하나의 클래스로 모을 수 있습니다.
예를 들어 UserController 클래스는 사용자의 표시·생성·갱신·삭제 등 사용자에 관한 모든 수신 요청을 처리할 수 있습니다.
기본적으로 컨트롤러는 app/Http/Controllers 디렉터리에 저장됩니다.
컨트롤러 생성
새 컨트롤러를 빠르게 생성하려면 make:controller Artisan 명령을 사용합니다.
애플리케이션의 모든 컨트롤러는 기본적으로 app/Http/Controllers 디렉터리에 저장됩니다.
php artisan make:controller UserController
기본 컨트롤러
컨트롤러 클래스는 수신하는 HTTP 요청에 응답하는 여러 public 메서드를 가질 수 있습니다.
<? php
namespace App\Http\Controllers ;
use App\Models\ User ;
use Illuminate\View\ View ;
class UserController extends Controller
{
/**
* 지정된 사용자의 프로필을 표시한다
*/
public function show ( string $id ) : View
{
return view ( 'user.profile' , [
'user' => User :: findOrFail ( $id )
]);
}
}
컨트롤러 클래스와 메서드를 생성한 후에는 다음과 같이 컨트롤러 메서드로의 라우트를 정의할 수 있습니다.
use App\Http\Controllers\ UserController ;
Route :: get ( '/user/{id}' , [ UserController :: class , 'show' ]);
수신 요청이 지정된 라우트 URI와 일치하면 App\Http\Controllers\UserController 클래스의 show 메서드가 호출되고, 라우트 파라미터가 메서드로 전달됩니다.
컨트롤러는 베이스 클래스를 상속할 필요는 없습니다. 다만 모든 컨트롤러에서 공유해야 할 메서드를 가진 베이스 컨트롤러 클래스를 상속하면 편리한 경우가 있습니다.
싱글 액션 컨트롤러
컨트롤러의 액션이 특히 복잡한 경우, 컨트롤러 클래스 전체를 그 단일 액션에 전념시키면 편리합니다.
이를 실현하려면 컨트롤러 안에 단일 __invoke 메서드를 정의합니다.
<? php
namespace App\Http\Controllers ;
class ProvisionServer extends Controller
{
/**
* 새 웹 서버를 프로비저닝한다
*/
public function __invoke ()
{
// ...
}
}
싱글 액션 컨트롤러의 라우트를 등록하는 경우, 컨트롤러 메서드를 지정할 필요는 없습니다.
컨트롤러명만 라우터에 전달합니다.
use App\Http\Controllers\ ProvisionServer ;
Route :: post ( '/server' , ProvisionServer :: class );
make:controller Artisan 명령의 --invokable 옵션을 사용해 호출 가능한 컨트롤러를 생성할 수 있습니다.
php artisan make:controller ProvisionServer --invokable
리소스 컨트롤러
애플리케이션 내의 각 Eloquent 모델을 “리소스”라고 생각하면, 각 리소스에 대해 동일한 조작 세트(CRUD)를 실행하는 것이 일반적입니다.
Laravel의 리소스 라우팅은 전형적인 생성·읽기·갱신·삭제(CRUD) 라우트를 한 줄의 코드로 컨트롤러에 할당합니다.
make:controller Artisan 명령의 --resource 옵션을 사용해 이 액션들을 처리하는 컨트롤러를 빠르게 생성할 수 있습니다.
php artisan make:controller PhotoController --resource
이 명령은 app/Http/Controllers/PhotoController.php에 컨트롤러를 생성합니다.
컨트롤러에는 사용 가능한 각 리소스 조작의 메서드가 스텁으로 포함됩니다.
다음으로 컨트롤러를 가리키는 리소스 라우트를 등록합니다.
use App\Http\Controllers\ PhotoController ;
Route :: resource ( 'photos' , PhotoController :: class );
이 한 줄의 라우트 선언으로 리소스로의 다양한 액션을 처리하는 여러 라우트가 생성됩니다.
생성된 컨트롤러에는 이 각 액션의 메서드가 이미 스텁으로 포함되어 있습니다.
HTTP 메서드 URI 액션 라우트 이름 GET /photosindex photos.index GET /photos/createcreate photos.create POST /photosstore photos.store GET /photos/{photo}show photos.show GET /photos/{photo}/editedit photos.edit PUT/PATCH /photos/{photo}update photos.update DELETE /photos/{photo}destroy photos.destroy
php artisan route:list 명령을 실행하면 애플리케이션 라우트의 개요를 빠르게 확인할 수 있습니다.
부분적 리소스 라우트
리소스 라우트를 선언할 때 컨트롤러가 처리해야 할 액션의 서브셋을 지정할 수 있습니다.
use App\Http\Controllers\ PhotoController ;
Route :: resource ( 'photos' , PhotoController :: class ) -> only ([
'index' , 'show'
]);
Route :: resource ( 'photos' , PhotoController :: class ) -> except ([
'create' , 'store' , 'update' , 'destroy'
]);
API 리소스 라우트
API에서 사용하는 리소스 라우트를 선언하는 경우, create나 edit 같이 HTML 템플릿을 표시하는 라우트를 제외하고 싶은 경우가 많습니다.
apiResource 메서드를 사용하면 이 두 라우트를 자동으로 제외할 수 있습니다.
use App\Http\Controllers\ PhotoController ;
Route :: apiResource ( 'photos' , PhotoController :: class );
의존성 주입
생성자 주입
Laravel의 서비스 컨테이너는 모든 Laravel 컨트롤러의 의존 해결에 사용됩니다.
따라서 컨트롤러의 생성자에 컨트롤러가 필요로 하는 의존을 타입 힌트로 지정할 수 있습니다.
선언된 의존은 자동으로 해결되어 컨트롤러 인스턴스에 주입됩니다.
<? php
namespace App\Http\Controllers ;
use App\Repositories\ UserRepository ;
class UserController extends Controller
{
/**
* 새 컨트롤러 인스턴스의 생성
*/
public function __construct (
protected UserRepository $users ,
) {}
}
메서드 주입
생성자 주입에 더해 컨트롤러의 메서드의 의존도 타입 힌트로 지정할 수 있습니다.
메서드 주입의 일반적인 유스케이스는 Illuminate\Http\Request 인스턴스를 컨트롤러 메서드에 주입하는 것입니다.
<? php
namespace App\Http\Controllers ;
use Illuminate\Http\ RedirectResponse ;
use Illuminate\Http\ Request ;
class UserController extends Controller
{
/**
* 새 사용자를 저장한다
*/
public function store ( Request $request ) : RedirectResponse
{
$name = $request -> name ;
// 사용자를 저장하는 처리...
return redirect ( '/users' );
}
}
컨트롤러 메서드가 라우트 파라미터로부터의 입력도 받는 경우에는, 다른 의존 뒤에 라우트 인수를 나열합니다.
예를 들어 라우트가 다음과 같이 정의되어 있는 경우를 생각합니다.
use App\Http\Controllers\ UserController ;
Route :: put ( '/user/{id}' , [ UserController :: class , 'update' ]);
다음과 같이 컨트롤러 메서드를 정의함으로써 Illuminate\Http\Request를 타입 힌트하면서 id 파라미터에도 접근할 수 있습니다.
<? php
namespace App\Http\Controllers ;
use Illuminate\Http\ RedirectResponse ;
use Illuminate\Http\ Request ;
class UserController extends Controller
{
/**
* 지정된 사용자를 갱신한다
*/
public function update ( Request $request , string $id ) : RedirectResponse
{
// 사용자를 갱신하는 처리...
return redirect ( '/users' );
}
}
의존성 주입을 활용함으로써 테스트 시에 모의 객체를 끼워 넣기 쉬워지고, 코드의 테스트 용이성이 향상됩니다.
다음 단계
라우팅 라우트 정의 방법과 컨트롤러와의 연동을 되짚어 봅니다.