메인 콘텐츠로 건너뛰기

컨트롤러란

라우트 파일에 모든 요청 처리 로직을 클로저로 정의하는 대신, “컨트롤러” 클래스를 사용해 이 동작을 정리할 수 있습니다. 컨트롤러는 관련된 요청 처리 로직을 하나의 클래스로 모을 수 있습니다. 예를 들어 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/photosindexphotos.index
GET/photos/createcreatephotos.create
POST/photosstorephotos.store
GET/photos/{photo}showphotos.show
GET/photos/{photo}/editeditphotos.edit
PUT/PATCH/photos/{photo}updatephotos.update
DELETE/photos/{photo}destroyphotos.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에서 사용하는 리소스 라우트를 선언하는 경우, createedit 같이 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');
    }
}
의존성 주입을 활용함으로써 테스트 시에 모의 객체를 끼워 넣기 쉬워지고, 코드의 테스트 용이성이 향상됩니다.

다음 단계

라우팅

라우트 정의 방법과 컨트롤러와의 연동을 되짚어 봅니다.
마지막 수정일 2026년 7월 13일