> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 세션

> Laravel의 HTTP 세션을 사용해 요청 간에 데이터를 유지하는 방법

## 세션이란

HTTP는 스테이트리스한 프로토콜입니다. 즉, 요청 사이에 사용자의 정보를 유지하는 구조가 HTTP 자체에는 없습니다.
Laravel의 세션 기능은 여러 요청에 걸쳐 사용자의 데이터를 유지하는 수단을 제공합니다.

로그인 상태, 카트 내 상품, 폼 입력 중 데이터 등 요청 사이에 유지하고 싶은 정보를 세션에 저장합니다.

## 세션 드라이버 설정

세션 설정은 `config/session.php`에 작성되어 있습니다.
`SESSION_DRIVER` 환경 변수(`.env` 파일)로 드라이버를 전환할 수 있습니다.

```ini theme={null}
SESSION_DRIVER=database
```

Laravel이 기본으로 지원하는 드라이버는 다음과 같습니다.

| 드라이버       | 개요                                        |
| ---------- | ----------------------------------------- |
| `file`     | `storage/framework/sessions`에 파일로 저장(기본값) |
| `cookie`   | 암호화된 쿠키로 브라우저에 저장                         |
| `database` | 데이터베이스 테이블에 저장                            |
| `redis`    | Redis에 저장(고속)                             |
| `array`    | PHP 배열에 저장(테스트용. 요청 사이에 유지되지 않음)          |

<Info>
  Laravel의 기본 프로젝트에서는 `database` 드라이버가 설정되어 있습니다. `database` 드라이버를 사용하는 경우 `sessions` 테이블이 필요하지만, 기본 마이그레이션에 포함되어 있으므로 그대로 사용할 수 있습니다.
</Info>

## 세션 접근 방법

세션에 접근하려면 `Request` 인스턴스의 메서드를 사용하는 방법과 글로벌 헬퍼 `session()`을 사용하는 방법 두 가지가 있습니다.

### Request 인스턴스를 사용하는 방법

컨트롤러의 메서드에 `Request`를 타입 힌트로 받고, `$request->session()`으로 세션에 접근합니다.

```php theme={null}
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\View\View;

class DashboardController extends Controller
{
    public function index(Request $request): View
    {
        $username = $request->session()->get('username');

        return view('dashboard', ['username' => $username]);
    }
}
```

### 글로벌 헬퍼 `session()`을 사용하는 방법

`session()` 헬퍼 함수는 컨트롤러나 뷰 등 어디서든 호출할 수 있습니다.

```php theme={null}
// 값을 가져온다
$value = session('key');

// 기본값과 함께 가져온다
$value = session('key', '기본값');

// 값을 저장한다
session(['key' => 'value']);
```

<Tip>
  어느 방법이든 테스트 시에 `assertSessionHas` 메서드로 검증할 수 있습니다. 컨트롤러 안에서는 `$request->session()`을 사용하면 의존 관계가 명시되어 알기 쉬워집니다.
</Tip>

## 세션 조작

### 데이터 가져오기

```php theme={null}
// 키를 지정해서 가져오기
$value = $request->session()->get('key');

// 기본값을 지정한다
$value = $request->session()->get('key', 'default');

// 기본값을 클로저로 지정한다
$value = $request->session()->get('key', function () {
    return 'default';
});

// 모든 세션 데이터를 가져온다
$data = $request->session()->all();
```

### 데이터 존재 체크

```php theme={null}
// 값이 존재하고 null이 아닐 경우에 true
if ($request->session()->has('user_id')) {
    // ...
}

// null이라도 존재하면 true
if ($request->session()->exists('user_id')) {
    // ...
}

// 존재하지 않는 경우에 true
if ($request->session()->missing('user_id')) {
    // ...
}
```

`has`와 `exists`의 차이에 주의해 주세요.

| 메서드      | `null`인 경우  |
| -------- | ----------- |
| `has`    | `false`를 반환 |
| `exists` | `true`를 반환  |

### 데이터 저장

```php theme={null}
// Request 인스턴스 경유
$request->session()->put('user_name', '김철수');

// 글로벌 헬퍼 경유
session(['user_name' => '김철수']);

// 배열에 추가
$request->session()->push('cart.items', ['id' => 1, 'name' => '상품A']);
```

### 데이터 삭제

```php theme={null}
// 특정 키를 삭제한다
$request->session()->forget('user_name');

// 여러 키를 함께 삭제한다
$request->session()->forget(['user_name', 'cart']);

// 모든 세션 데이터를 삭제한다
$request->session()->flush();
```

## 플래시 데이터

플래시 데이터는 **다음 요청에서만** 유효한 세션 데이터입니다.
폼 전송 완료 메시지나 오류 메시지 등 한 번만 표시하고 싶은 정보에 사용합니다.

### `flash()`로 데이터 저장

```php theme={null}
$request->session()->flash('status', '게시물을 저장했습니다.');
```

이 데이터는 다음 요청에서 참조할 수 있지만, 그 후에는 자동으로 삭제됩니다.

### 플래시 데이터 연장

```php theme={null}
// 모든 플래시 데이터를 한 번 더 요청 연장한다
$request->session()->reflash();

// 특정 키만 연장한다
$request->session()->keep(['status', 'message']);
```

### Blade에서 플래시 메시지 표시

```blade theme={null}
{{-- resources/views/layouts/app.blade.php --}}

@if (session('success'))
    <div class="alert alert-success">
        {{ session('success') }}
    </div>
@endif

@if (session('error'))
    <div class="alert alert-danger">
        {{ session('error') }}
    </div>
@endif
```

<Tip>
  플래시 메시지 표시는 레이아웃 파일(`layouts/app.blade.php` 등)에 작성해 두면 모든 페이지에서 일관되게 표시됩니다.
</Tip>

## 실용 예시: 폼 전송 후의 메시지 표시

폼을 전송한 후 성공 메시지를 세션에 저장해 리다이렉트하고, 다음 페이지에서 표시하는 것은 웹 앱의 정석 패턴입니다.

<Steps>
  <Step title="라우트 정의">
    ```php theme={null}
    use App\Http\Controllers\PostController;

    Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
    Route::get('/posts/create', [PostController::class, 'create'])->name('posts.create');
    Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
    ```
  </Step>

  <Step title="컨트롤러 구현">
    폼 전송을 받는 `store` 메서드에서 저장 후 성공 메시지를 붙여 리다이렉트합니다.

    ```php theme={null}
    <?php

    namespace App\Http\Controllers;

    use App\Models\Post;
    use Illuminate\Http\RedirectResponse;
    use Illuminate\Http\Request;
    use Illuminate\View\View;

    class PostController extends Controller
    {
        public function index(): View
        {
            $posts = Post::latest()->get();

            return view('posts.index', ['posts' => $posts]);
        }

        public function create(): View
        {
            return view('posts.create');
        }

        public function store(Request $request): RedirectResponse
        {
            $validated = $request->validate([
                'title' => 'required|string|max:255',
                'body'  => 'required|string',
            ]);

            Post::create($validated);

            return redirect()
                ->route('posts.index')
                ->with('success', '게시물을 생성했습니다.');
        }
    }
    ```

    `redirect()->with('success', '...')`는 리다이렉트 대상으로 플래시 데이터를 전달하는 단축 구문입니다.
  </Step>

  <Step title="레이아웃에서 메시지 표시">
    `resources/views/layouts/app.blade.php`에 플래시 메시지의 표시 부분을 추가합니다.

    ```blade theme={null}
    <!DOCTYPE html>
    <html>
    <head>
        <title>My App</title>
    </head>
    <body>
        {{-- 플래시 메시지 --}}
        @if (session('success'))
            <div class="alert alert-success">
                {{ session('success') }}
            </div>
        @endif

        @if (session('error'))
            <div class="alert alert-danger">
                {{ session('error') }}
            </div>
        @endif

        @yield('content')
    </body>
    </html>
    ```
  </Step>

  <Step title="목록 페이지의 뷰를 생성">
    ```blade theme={null}
    {{-- resources/views/posts/index.blade.php --}}

    @extends('layouts.app')

    @section('content')
    <h1>게시물 목록</h1>

    @foreach ($posts as $post)
        <div>
            <h2>{{ $post->title }}</h2>
            <p>{{ $post->body }}</p>
        </div>
    @endforeach
    @endsection
    ```

    게시물이 저장되어 리다이렉트되면 이 목록 페이지 상단에 "게시물을 생성했습니다."라는 메시지가 한 번만 표시됩니다.
  </Step>
</Steps>

### 유효성 검증 오류와 조합한 패턴

유효성 검증 실패 시에는 `back()->withErrors()`와 조합해 사용합니다.
Laravel은 유효성 검증 실패 시 자동으로 오류를 플래시 데이터로 유지하므로 Blade에서 `$errors` 변수를 사용할 수 있습니다.

```php theme={null}
public function store(Request $request): RedirectResponse
{
    $validated = $request->validate([
        'title' => 'required|string|max:255',
        'body'  => 'required|string',
    ]);

    Post::create($validated);

    // 성공 시: 플래시 메시지와 함께 리다이렉트
    return redirect()
        ->route('posts.index')
        ->with('success', '게시물을 생성했습니다.');

    // 유효성 검증 실패 시에는 Laravel이 자동으로 back()->withErrors()->withInput()을 실행한다
}
```

```blade theme={null}
{{-- 폼 페이지 --}}

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif

<form method="POST" action="{{ route('posts.store') }}">
    @csrf

    <div>
        <label for="title">제목</label>
        <input
            id="title"
            type="text"
            name="title"
            value="{{ old('title') }}"
        />
        @error('title')
            <span>{{ $message }}</span>
        @enderror
    </div>

    <div>
        <label for="body">본문</label>
        <textarea id="body" name="body">{{ old('body') }}</textarea>
        @error('body')
            <span>{{ $message }}</span>
        @enderror
    </div>

    <button type="submit">게시</button>
</form>
```

<Warning>
  `flush()`는 세션의 모든 데이터를 삭제합니다. 로그인 상태 등도 잃게 되므로 사용자의 데이터만 삭제하고 싶은 경우에는 `forget()`으로 특정 키를 지정해 주세요.
</Warning>

## 다음 단계

<Card title="유효성 검증" icon="check-circle" href="/ko/validation">
  폼의 입력 데이터를 유효성 검증으로 검사하는 방법을 확인합니다.
</Card>


## Related topics

- [세션 재개](/ko/packages/laravel-copilot-sdk/resume.md)
- [세션 훅](/ko/packages/laravel-copilot-sdk/hooks.md)
- [세션 라이프사이클 이벤트](/ko/packages/laravel-copilot-sdk/session-lifecycle-event.md)
- [세션 컨텍스트와 필터링](/ko/packages/laravel-copilot-sdk/session-context.md)
- [HTTP 테스트](/ko/http-tests.md)
