편집을 취소할 수 있습니다. 이 편집을 되돌리려면 아래의 바뀐 내용을 확인한 후 게시해주세요.
최신판 | 당신의 편집 | ||
6번째 줄: | 6번째 줄: | ||
==소개== | ==소개== | ||
이 빠른 시작 가이드는 Laravel 프레임워크에 대한 중급 소개를 제공하며, 데이터베이스 마이그레이션, Eloquent ORM, 라우팅, 인증, | 이 빠른 시작 가이드는 Laravel 프레임워크에 대한 중급 소개를 제공하며, 데이터베이스 마이그레이션, Eloquent ORM, 라우팅, 인증, 인, 의존성 주입, 검증, 뷰, Blade 템플릿에 대한 내용을 포함하고 있습니다. Laravel 프레임워크나 PHP 프레임워크에 대한 기본 지식이 있는 경우, 이 가이드를 시작하기에 적합합니다. | ||
Laravel의 기본 기능들을 샘플로 다루어 보기 위해, 태스크들을 다루는 태스크 목록 애플리케이션을 만들어 보겠습니다. 즉, 전형적인 "할 일" 목록 예제를 다루게 됩니다. [[Laravel | Laravel의 기본 기능들을 샘플로 다루어 보기 위해, 태스크들을 다루는 태스크 목록 애플리케이션을 만들어 보겠습니다. 즉, 전형적인 "할 일" 목록 예제를 다루게 됩니다. [[Laravel 기본 태스크 목록 |"기본" 빠른 시작]]과 달리, 이 튜토리얼에서는 사용자가 계정을 만들고 애플리케이션에 인증할 수 있도록 할 것입니다. 이 프로젝트의 완성된 소스코드는 [https://github.com/laravel/quickstart-intermediate GitHub에서 확인]할 수 있습니다. | ||
== | ==도커 환경== | ||
<syntaxhighlight lang='console'> | <syntaxhighlight lang='console'> | ||
testuser@lcoalhost:~$ mkdir ~/workspace && cd ~/workspace | |||
testuser@localhost:~/workspace$ docker run --name laravel --rm -it -v ${PWD}:/workspace -w /workspace --entrypoint="" --network host bitnami/laravel:latest bash | |||
Unable to find image 'bitnami/laravel:latest' locally | Unable to find image 'bitnami/laravel:latest' locally | ||
latest: Pulling from bitnami/laravel | latest: Pulling from bitnami/laravel | ||
28번째 줄: | 19번째 줄: | ||
Digest: sha256:d16af27a0d4c2f6f3f71c730d7def97de91e0b2ea0233e84dc758340521b1629 | Digest: sha256:d16af27a0d4c2f6f3f71c730d7def97de91e0b2ea0233e84dc758340521b1629 | ||
Status: Downloaded newer image for bitnami/laravel:latest | Status: Downloaded newer image for bitnami/laravel:latest | ||
root@ | root@localhost:/workspace# | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | ==설치== | ||
환경이 준비되면 Composer를 사용하여 Laravel 프레임워크를 설치할 수 있습니다: | 우선, Laravel 프레임워크을 새로 설치해야 합니다. [[Laravel Homestead|Homestead 가상머신]]을 사용하거나 선택한 로컬 PHP 환경을 사용하여 프레임워크를 실행할 수 있습니다. 로컬 환경이 준비되면 Composer를 사용하여 Laravel 프레임워크를 설치할 수 있습니다: | ||
<syntaxhighlight lang='bash'> | <syntaxhighlight lang='bash'> | ||
39번째 줄: | 30번째 줄: | ||
<syntaxhighlight lang='console'> | <syntaxhighlight lang='console'> | ||
root@ | root@localhost:/workspace# composer create-project laravel/laravel quickstart --prefer-dist | ||
Creating a "laravel/laravel" project at "./quickstart" | Creating a "laravel/laravel" project at "./quickstart" | ||
Installing laravel/laravel (v11.1.1) | Installing laravel/laravel (v11.1.1) | ||
54번째 줄: | 45번째 줄: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
<syntaxhighlight lang='console'> | <syntaxhighlight lang='console'> | ||
root@ | root@localhost:/workspace# cd quickstart/ | ||
root@ | root@localhost:/workspace/quickstart# find app/ routes/ resources/ | grep .php | ||
app/Providers/AppServiceProvider.php | app/Providers/AppServiceProvider.php | ||
app/Http/Controllers/Controller.php | app/Http/Controllers/Controller.php | ||
62번째 줄: | 53번째 줄: | ||
routes/web.php | routes/web.php | ||
resources/views/welcome.blade.php | resources/views/welcome.blade.php | ||
</syntaxhighlight> | </syntaxhighlight> | ||
'''참고''': [[composer create-project laravel/laravel quickstart --prefer-dist]] | '''참고''': [[composer create-project laravel/laravel quickstart --prefer-dist]] | ||
==데이터베이스 준비== | ==데이터베이스 준비== | ||
278번째 줄: | 248번째 줄: | ||
==라우팅== | ==라우팅== | ||
태스크 목록 애플리케이션의 [[Laravel | 태스크 목록 애플리케이션의 [[Laravel 기본 태스크 목록|기본 버전]]에서는 <code>routes/web.php</code> 파일 내에서 클로저를 사용하여 모든 로직을 정의했습니다. 여기서는 주로 [[Laravel 컨트롤러|컨트롤러]]를 사용하여 라우트를 조직할 것입니다. 컨트롤러를 사용하면 HTTP 요청 처리 로직을 여러 파일에 걸쳐 분산시켜 더 나은 조직화를 할 수 있습니다. | ||
===뷰 표시하기=== | ===뷰 표시하기=== | ||
단일 라우트를 사용하여 클로저를 구현할 것입니다. 이는 애플리케이션의 게스트를 위한 랜딩 페이지가 될 <code>/</code> 라우트입니다. 그럼, <code>/</code> 라우트를 작성해 봅시다. 이 라우트에서는 "welcome" 페이지를 포함하는 HTML 템플릿을 렌더링하고자 합니다. | |||
Laravel에서는 모든 HTML 템플릿은 <code>resources/views</code> 디렉토리에 저장되며, <code>view</code> 헬퍼를 사용하여 이 템플릿 중 하나를 라우트에서 반환할 수 있습니다: | Laravel에서는 모든 HTML 템플릿은 <code>resources/views</code> 디렉토리에 저장되며, <code>view</code> 헬퍼를 사용하여 이 템플릿 중 하나를 라우트에서 반환할 수 있습니다: | ||
287번째 줄: | 257번째 줄: | ||
{{소스헤더|routes/web.php}} | {{소스헤더|routes/web.php}} | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
Route::get('/', function () { | Route::get('/', function () { | ||
return view('welcome'); | return view('welcome'); | ||
301번째 줄: | 267번째 줄: | ||
사용자가 계정을 만들고 애플리케이션에 로그인할 수 있도록 하는 것도 필요합니다. 일반적으로 웹 애플리케이션에 전체 인증 레이어를 구축하는 것은 번거로운 작업일 수 있습니다. 그러나 이는 매우 일반적인 요구사항입니다. | 사용자가 계정을 만들고 애플리케이션에 로그인할 수 있도록 하는 것도 필요합니다. 일반적으로 웹 애플리케이션에 전체 인증 레이어를 구축하는 것은 번거로운 작업일 수 있습니다. 그러나 이는 매우 일반적인 요구사항입니다. | ||
;라우트 설정 | |||
<code>routes/web.php</code> 파일에 라우트를 추가합니다. | <code>routes/web.php</code> 파일에 라우트를 추가합니다. | ||
323번째 줄: | 289번째 줄: | ||
Route::middleware(['auth'])->group(function () { | Route::middleware(['auth'])->group(function () { | ||
Route::view('/dashboard', 'dashboard'); | Route::view('/dashboard', 'dashboard')->name('dashboard'); | ||
}); | }); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
;인증 컨트롤러 생성 | |||
<syntaxhighlight lang='bash'> | <syntaxhighlight lang='bash'> | ||
php artisan make:controller AuthController | php artisan make:controller AuthController | ||
333번째 줄: | 299번째 줄: | ||
{{소스헤더|app/Http/Controllers/AuthController.php}} | {{소스헤더|app/Http/Controllers/AuthController.php}} | ||
<syntaxhighlight lang='php | <syntaxhighlight lang='php'> | ||
<?php | <?php | ||
400번째 줄: | 366번째 줄: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
;로그인 뷰 작성 | |||
{{소스헤더|resources/views/auth/login.blade.php}} | {{소스헤더|resources/views/auth/login.blade.php}} | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
<!DOCTYPE html> | <!DOCTYPE html> | ||
<html> | <html> | ||
<head> | <head> | ||
<title>Login</title> | <title>Login</title> | ||
</head> | </head> | ||
<body> | <body> | ||
<h2>Login</h2> | <h2>Login</h2> | ||
@if($errors->any()) | @if($errors->any()) | ||
<div> | |||
<ul> | |||
@foreach ($errors->all() as $error) | |||
<li>{{ $error }}</li> | |||
@endforeach | |||
</ul> | |||
</div> | |||
@endif | @endif | ||
440번째 줄: | 404번째 줄: | ||
</form> | </form> | ||
</body> | </body> | ||
</html> | </html> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
;회원가입 뷰 작성 | |||
{{소스헤더|resources/views/auth/register.blade.php}} | {{소스헤더|resources/views/auth/register.blade.php}} | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
<!DOCTYPE html> | <!DOCTYPE html> | ||
<html> | <html> | ||
<head> | <head> | ||
<title>Register</title> | <title>Register</title> | ||
</head> | </head> | ||
<body> | <body> | ||
<h2>Register</h2> | <h2>Register</h2> | ||
@if($errors->any()) | @if($errors->any()) | ||
<div> | |||
<ul> | |||
@foreach ($errors->all() as $error) | |||
<li>{{ $error }}</li> | |||
@endforeach | |||
</ul> | |||
</div> | |||
@endif | @endif | ||
494번째 줄: | 455번째 줄: | ||
</form> | </form> | ||
</body> | </body> | ||
</html> | </html> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
;대시보드 뷰 작성 | |||
{{소스헤더|resources/views/dashboard.blade.php}} | {{소스헤더|resources/views/dashboard.blade.php}} | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
<!DOCTYPE html> | <!DOCTYPE html> | ||
<html> | <html> | ||
<head> | <head> | ||
<title>Dashboard</title> | <title>Dashboard</title> | ||
</head> | </head> | ||
<body> | <body> | ||
<h2>Dashboard</h2> | <h2>Dashboard</h2> | ||
516번째 줄: | 474번째 줄: | ||
<button type="submit">Logout</button> | <button type="submit">Logout</button> | ||
</form> | </form> | ||
</body> | </body> | ||
</html> | </html> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
536번째 줄: | 491번째 줄: | ||
컨트롤러가 생성되었으니, <code>routes/web.php</code> 파일에 컨트롤러를 가리키는 몇 가지 라우트를 추가해 봅시다: | 컨트롤러가 생성되었으니, <code>routes/web.php</code> 파일에 컨트롤러를 가리키는 몇 가지 라우트를 추가해 봅시다: | ||
{{소스헤더|routes/web.php}} | {{소스헤더|routes/web.php}} | ||
<syntaxhighlight lang='php' highlight='4,9 | <syntaxhighlight lang='php' highlight='4,7-9'> | ||
<?php | <?php | ||
547번째 줄: | 500번째 줄: | ||
use Illuminate\Support\Facades\Route; | use Illuminate\Support\Facades\Route; | ||
... | ... | ||
Route::get('/tasks', [TaskController::class, 'index']); | |||
Route::post('/task', [TaskController::class, 'store']); | |||
Route::delete('/task/{task}', [TaskController::class, 'destroy']); | |||
</syntaxhighlight> | |||
;모든 태스크 라우트 인증하기 | |||
이 애플리케이션에서는 모든 태스크 라우트가 인증된 사용자만 접근할 수 있도록 하고 싶습니다. 즉, 사용자가 태스크를 생성하려면 애플리케이션에 "로그인"해야 합니다. Laravel에서는 미들웨어를 사용하여 이러한 작업을 간단하게 할 수 있습니다. | |||
컨트롤러의 모든 액션에 대해 인증된 사용자만 접근할 수 있도록 하려면, 컨트롤러 생성자에서 <code>middleware</code> 메소드를 호출하면 됩니다. 사용가능한 모든 라우트 미들웨어는 <code>app/Http/Kernel.php</code> 파일에 정의되어 있습니다. 이 경우에는, 모든 액션에 <code>auth</code> 미들웨어를 할당하고자 합니다: | |||
<syntaxhighlight lang='php'> | |||
<?php | |||
namespace App\Http\Controllers; | |||
use App\Http\Requests; | |||
use Illuminate\Http\Request; | |||
use App\Http\Controllers\Controller; | |||
class TaskController extends Controller | |||
{ | |||
/** | |||
* 새 컨트롤러 인스턴스를 생성합니다. | |||
* | |||
* @return void | |||
*/ | |||
public function __construct() | |||
{ | |||
$this->middleware('auth'); | |||
} | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
567번째 줄: | 545번째 줄: | ||
우리의 <code>app.blade.php</code> 뷰는 다음과 같이 생겼습니다: | 우리의 <code>app.blade.php</code> 뷰는 다음과 같이 생겼습니다: | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
<!-- resources/views/layouts/app.blade.php --> | |||
<!DOCTYPE html> | <!DOCTYPE html> | ||
<html lang="en"> | <html lang="en"> | ||
<head> | |||
<head> | <title>Laravel Quickstart - Intermediate</title> | ||
<!-- CSS And JavaScript --> | |||
</head> | </head> | ||
<body> | <body> | ||
<div class="container"> | |||
<nav class="navbar navbar-default"> | |||
<!-- Navbar Contents --> | |||
</nav> | |||
</div> | </div> | ||
@yield('content') | |||
</body> | |||
</body> | |||
</html> | </html> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
597번째 줄: | 575번째 줄: | ||
Bootstrap CSS 보일러플레이트 코드는 생략하고 중요한 부분에 집중하겠습니다. 애플리케이션의 전체 소스 코드는 [https://github.com/laravel/quickstart-intermediate GitHub]에서 다운로드할 수 있습니다: | Bootstrap CSS 보일러플레이트 코드는 생략하고 중요한 부분에 집중하겠습니다. 애플리케이션의 전체 소스 코드는 [https://github.com/laravel/quickstart-intermediate GitHub]에서 다운로드할 수 있습니다: | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
<!-- resources/views/tasks/index.blade.php --> | |||
@extends('layouts.app') | @extends('layouts.app') | ||
@section('content') | @section('content') | ||
<!-- Bootstrap Boilerplate... --> | <!-- Bootstrap Boilerplate... --> | ||
<div class="panel-body"> | |||
<div class=" | |||
<!-- Display Validation Errors --> | <!-- Display Validation Errors --> | ||
@include('common.errors') | @include('common.errors') | ||
<!-- New Task Form --> | <!-- New Task Form --> | ||
<form action="{{ url('task') }}" method="POST" class="form-horizontal"> | <form action="{{ url('task') }}" method="POST" class="form-horizontal"> | ||
{{ csrf_field() }} | {{ csrf_field() }} | ||
<!-- Task Name --> | <!-- Task Name --> | ||
<div class=" | <div class="form-group"> | ||
<label for="task">Task</label> | <label for="task-name" class="col-sm-3 control-label">Task</label> | ||
<input type="text" name="name" id="task" class="form-control"> | |||
<div class="col-sm-6"> | |||
<input type="text" name="name" id="task-name" class="form-control"> | |||
</div> | |||
</div> | </div> | ||
<!-- Add Task Button --> | <!-- Add Task Button --> | ||
<button type="submit" class="btn btn- | <div class="form-group"> | ||
<div class="col-sm-offset-3 col-sm-6"> | |||
</ | <button type="submit" class="btn btn-default"> | ||
<i class="fa fa-plus"></i> Add Task | |||
</button> | |||
</div> | |||
</div> | |||
</form> | </form> | ||
</div> | </div> | ||
<!-- TODO: Current Tasks --> | |||
<!-- TODO: Current Tasks --> | |||
@endsection | @endsection | ||
</syntaxhighlight> | </syntaxhighlight> | ||
642번째 줄: | 623번째 줄: | ||
이제 애플리케이션을 위한 기본 레이아웃과 뷰를 정의했습니다. 다음으로, <code>TaskController</code>의 <code>index</code> 메소드에서 이 뷰를 반환하도록 하겠습니다: | 이제 애플리케이션을 위한 기본 레이아웃과 뷰를 정의했습니다. 다음으로, <code>TaskController</code>의 <code>index</code> 메소드에서 이 뷰를 반환하도록 하겠습니다: | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
/** | |||
* 사용자의 모든 태스크 목록을 표시합니다. | |||
* | |||
* @param Request $request | |||
* @return Response | |||
*/ | |||
public function index(Request $request) | |||
{ | |||
return view('tasks.index'); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
664번째 줄: | 644번째 줄: | ||
이 폼에서는 <code>name</code> 필드를 필수로 하고, <code>255</code>자 이하로 입력되도록 해야 합니다. 검증에 실패하면 사용자를 <code>/tasks</code> URL로 리디렉션하고, 이전 입력과 오류를 [[Laravel 세션|세션]]에 플래시해야 합니다. | 이 폼에서는 <code>name</code> 필드를 필수로 하고, <code>255</code>자 이하로 입력되도록 해야 합니다. 검증에 실패하면 사용자를 <code>/tasks</code> URL로 리디렉션하고, 이전 입력과 오류를 [[Laravel 세션|세션]]에 플래시해야 합니다. | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
/** | |||
* 새 태스크를 생성합니다. | |||
* | |||
* @param Request $request | |||
* @return Response | |||
*/ | |||
public function store(Request $request) | |||
{ | |||
$this->validate($request, [ | |||
'name' => 'required|max:255', | |||
]); | |||
// 태스크 생성... | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
[[Laravel | [[Laravel 기본 태스크 목록|기본 빠른 시작]]와 비교해보면, 이 검증 코드가 상당히 다르게 보일 것입니다! 컨트롤러 내에서는 기본 Laravel 컨트롤러에 포함된 <code>ValidatesRequests</code> 트레이트의 편리함을 활용할 수 있습니다. 이 트레이트는 요청과 검증 규칙 배열을 받는 간단한 <code>validate</code> 메소드를 노출합니다. | ||
검증이 실패했는지 수동으로 확인하거나 수동으로 리디렉션할 필요도 없습니다. 주어진 규칙에 대해 검증이 실패하면, 사용자는 자동으로 원래 있던 곳으로 리디렉션되고 오류는 자동으로 세션에 플래시됩니다. 참 편리하죠! | 검증이 실패했는지 수동으로 확인하거나 수동으로 리디렉션할 필요도 없습니다. 주어진 규칙에 대해 검증이 실패하면, 사용자는 자동으로 원래 있던 곳으로 리디렉션되고 오류는 자동으로 세션에 플래시됩니다. 참 편리하죠! | ||
689번째 줄: | 668번째 줄: | ||
뷰 내에서 <code>@include('common.errors')</code> 지시어를 사용하여 폼의 검증 오류를 렌더링한 것을 기억하세요. <code>common.errors</code> 뷰는 모든 페이지에서 동일한 형식으로 검증 오류를 쉽게 표시할 수 있게 해줍니다. 이제 이 뷰의 내용을 정의해봅시다: | 뷰 내에서 <code>@include('common.errors')</code> 지시어를 사용하여 폼의 검증 오류를 렌더링한 것을 기억하세요. <code>common.errors</code> 뷰는 모든 페이지에서 동일한 형식으로 검증 오류를 쉽게 표시할 수 있게 해줍니다. 이제 이 뷰의 내용을 정의해봅시다: | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
<!-- resources/views/common/errors.blade.php --> | |||
@if (count($errors) > 0) | @if (count($errors) > 0) | ||
<!-- Form Error List --> | <!-- Form Error List --> | ||
<div class="alert alert-danger"> | <div class="alert alert-danger"> | ||
<strong>Whoops! Something went wrong!</strong> | |||
<br><br> | |||
<ul> | |||
@foreach ($errors->all() as $error) | |||
<li>{{ $error }}</li> | |||
@endforeach | |||
</ul> | |||
</div> | </div> | ||
@endif | @endif | ||
</syntaxhighlight> | </syntaxhighlight> | ||
714번째 줄: | 694번째 줄: | ||
Laravel의 대부분의 관계는 <code>create</code> 메소드를 노출하며, 이 메소드는 속성 배열을 받아 관련 모델의 외래 키 값을 데이터베이스에 저장하기 전에 자동으로 설정합니다. 이 경우에는, <code>create</code> 메소드는 주어진 태스크의 <code>user_id</code> 속성을 현재 인증된 사용자의 ID로 자동 설정할 것입니다. 현재 사용자를 <code>$request->user()</code>를 사용하여 접근하고 있습니다. | Laravel의 대부분의 관계는 <code>create</code> 메소드를 노출하며, 이 메소드는 속성 배열을 받아 관련 모델의 외래 키 값을 데이터베이스에 저장하기 전에 자동으로 설정합니다. 이 경우에는, <code>create</code> 메소드는 주어진 태스크의 <code>user_id</code> 속성을 현재 인증된 사용자의 ID로 자동 설정할 것입니다. 현재 사용자를 <code>$request->user()</code>를 사용하여 접근하고 있습니다. | ||
<syntaxhighlight lang='php'> | |||
<syntaxhighlight lang='php | /** | ||
* 새 태스크를 생성합니다. | |||
* | |||
* @param Request $request | |||
* @return Response | |||
*/ | |||
public function store(Request $request) | |||
{ | |||
$this->validate($request, [ | |||
'name' => 'required|max:255', | |||
]); | |||
$request->user()->tasks()->create([ | |||
'name' => $request->name, | |||
]); | |||
return redirect('/tasks'); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
741번째 줄: | 720번째 줄: | ||
먼저, <code>TaskController@index</code> 메소드를 수정하여 모든 기존 태스크를 뷰로 전달해야 합니다. <code>view</code> 함수는 뷰에서 사용가능한 데이터 배열을 두 번째 인수로 받아들이며, 배열의 각 키는 뷰 내에서 변수로 사용됩니다. 예를 들어, 다음과 같이 할 수 있습니다: | 먼저, <code>TaskController@index</code> 메소드를 수정하여 모든 기존 태스크를 뷰로 전달해야 합니다. <code>view</code> 함수는 뷰에서 사용가능한 데이터 배열을 두 번째 인수로 받아들이며, 배열의 각 키는 뷰 내에서 변수로 사용됩니다. 예를 들어, 다음과 같이 할 수 있습니다: | ||
<syntaxhighlight lang='php'> | |||
<syntaxhighlight lang='php | /** | ||
* 사용자의 모든 태스크 목록을 표시합니다. | |||
* | |||
* @param Request $request | |||
* @return Response | |||
*/ | |||
public function index(Request $request) | |||
{ | |||
$tasks = $request->user()->tasks()->get(); | |||
return view('tasks.index', [ | |||
'tasks' => $tasks, | |||
]); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
769번째 줄: | 747번째 줄: | ||
그러면, <code>app/Repositories</code> 디렉토리를 생성하고 <code>TaskRepository</code> 클래스를 추가합시다. Laravel의 모든 <code>app</code> 폴더는 PSR-4 자동로딩 표준을 사용하여 자동으로 로드되므로, 필요한 만큼의 추가 디렉토리를 자유롭게 생성할 수 있습니다: | 그러면, <code>app/Repositories</code> 디렉토리를 생성하고 <code>TaskRepository</code> 클래스를 추가합시다. Laravel의 모든 <code>app</code> 폴더는 PSR-4 자동로딩 표준을 사용하여 자동으로 로드되므로, 필요한 만큼의 추가 디렉토리를 자유롭게 생성할 수 있습니다: | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
<?php | <?php | ||
namespace App | namespace App\Repositories; | ||
use App | use App\User; | ||
class TaskRepository | class TaskRepository | ||
{ | { | ||
/** | /** | ||
* | * 주어진 사용자의 모든 작업을 가져옵니다. | ||
* | * | ||
* @param User $user | * @param User $user | ||
788번째 줄: | 765번째 줄: | ||
{ | { | ||
return $user->tasks() | return $user->tasks() | ||
->orderBy('created_at', 'asc') | |||
->get(); | |||
} | } | ||
} | } | ||
797번째 줄: | 774번째 줄: | ||
레포지토리가 정의되면, 단순히 <code>TaskController</code>의 생성자에서 이를 "타입 힌트"로 지정하고 <code>index</code> 라우트 내에서 활용할 수 있습니다. Laravel은 모든 컨트롤러를 해결하기 위해 컨테이너를 사용하므로, 의존성은 자동으로 컨트롤러 인스턴스에 주입될 것입니다: | 레포지토리가 정의되면, 단순히 <code>TaskController</code>의 생성자에서 이를 "타입 힌트"로 지정하고 <code>index</code> 라우트 내에서 활용할 수 있습니다. Laravel은 모든 컨트롤러를 해결하기 위해 컨테이너를 사용하므로, 의존성은 자동으로 컨트롤러 인스턴스에 주입될 것입니다: | ||
<syntaxhighlight lang='php'> | |||
<syntaxhighlight lang='php | |||
<?php | <?php | ||
namespace App\Http\Controllers; | namespace App\Http\Controllers; | ||
use App\Http\ | use App\Task; | ||
use App\Http\Requests; | |||
use Illuminate\Http\Request; | use Illuminate\Http\Request; | ||
use App\Http\Controllers\Controller; | |||
use App\Repositories\TaskRepository; | |||
class TaskController extends Controller | class TaskController extends Controller | ||
{ | { | ||
/** | /** | ||
* | * 태스크 리포지토리 인스턴스. | ||
* | * | ||
* @var TaskRepository | * @var TaskRepository | ||
*/ | */ | ||
protected $tasks; | protected $tasks; | ||
/** | /** | ||
* | * 새 컨트롤러 인스턴스를 생성합니다. | ||
* | * | ||
* @param TaskRepository $tasks | * @param TaskRepository $tasks | ||
823번째 줄: | 802번째 줄: | ||
public function __construct(TaskRepository $tasks) | public function __construct(TaskRepository $tasks) | ||
{ | { | ||
$this->middleware('auth'); | |||
$this->tasks = $tasks; | $this->tasks = $tasks; | ||
} | } | ||
/** | /** | ||
* | * 사용자의 모든 태스크 목록을 표시합니다. | ||
* | * | ||
* @param Request $request | * @param Request $request | ||
838번째 줄: | 819번째 줄: | ||
]); | ]); | ||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
845번째 줄: | 825번째 줄: | ||
데이터가 전달되면 <code>tasks/index.blade.php</code> 뷰에서 태스크를 테이블에 표시할 수 있습니다. <code>@foreach</code> Blade 구문을 사용하면 간결한 루프를 작성할 수 있으며, 이는 매우 빠른 순수 PHP 코드로 컴파일됩니다: | 데이터가 전달되면 <code>tasks/index.blade.php</code> 뷰에서 태스크를 테이블에 표시할 수 있습니다. <code>@foreach</code> Blade 구문을 사용하면 간결한 루프를 작성할 수 있으며, 이는 매우 빠른 순수 PHP 코드로 컴파일됩니다: | ||
<syntaxhighlight lang='php'> | |||
<syntaxhighlight lang='php | |||
@extends('layouts.app') | @extends('layouts.app') | ||
@section('content') | @section('content') | ||
... | <!-- 태스크 생성 폼... --> | ||
<!-- | |||
@if (count($tasks) > 0) | <!-- 현재 태스크들 --> | ||
<div class=" | @if (count($tasks) > 0) | ||
<div class="panel panel-default"> | |||
<div class="panel-heading"> | |||
Current Tasks | |||
</div> | |||
<div class="panel-body"> | |||
<table class="table table-striped task-table"> | |||
<!-- 테이블 헤더 --> | |||
<thead> | |||
<th>Task</th> | |||
<th> </th> | |||
</thead> | |||
<!-- 테이블 바디 --> | |||
<tbody> | |||
@foreach ($tasks as $task) | |||
<tr> | |||
<!-- 태스크 이름 --> | |||
<td class="table-text"> | |||
<div>{{ $task->name }}</div> | |||
</td> | |||
<td> | |||
<!-- TODO: 삭제 버튼 --> | |||
</td> | |||
</tr> | |||
@endforeach | |||
</tbody> | |||
</table> | |||
</div> | </div> | ||
@endif | </div> | ||
@endif | |||
@endsection | @endsection | ||
</syntaxhighlight> | </syntaxhighlight> | ||
895번째 줄: | 875번째 줄: | ||
<code>tasks/index.blade.php</code> 뷰에 각 행에 삭제 버튼을 추가해야 할 곳에 "TODO" 메모를 남겼습니다. 이제 각 행에 작은 단일 버튼 폼을 만들어 삭제 버튼을 추가해 보겠습니다. 버튼이 클릭되면 애플리케이션에 <code>DELETE /task</code> 요청이 전송되어 <code>TaskController@destroy</code> 메소드를 트리거하게 됩니다: | <code>tasks/index.blade.php</code> 뷰에 각 행에 삭제 버튼을 추가해야 할 곳에 "TODO" 메모를 남겼습니다. 이제 각 행에 작은 단일 버튼 폼을 만들어 삭제 버튼을 추가해 보겠습니다. 버튼이 클릭되면 애플리케이션에 <code>DELETE /task</code> 요청이 전송되어 <code>TaskController@destroy</code> 메소드를 트리거하게 됩니다: | ||
<syntaxhighlight lang='php'> | |||
<syntaxhighlight lang='php | <tr> | ||
<!-- 태스크 이름 --> | |||
<td class="table-text"> | |||
<div>{{ $task->name }}</div> | |||
</td> | |||
<!-- 삭제 버튼 --> | |||
<td> | |||
<form action="{{ url('task/'.$task->id) }}" method="POST"> | |||
{{ csrf_field() }} | |||
{{ method_field('DELETE') }} | |||
<button type="submit" id="delete-task-{{ $task->id }}" class="btn btn-danger"> | |||
<i class="fa fa-btn fa-trash"></i>Delete | |||
</button> | |||
</form> | |||
</td> | |||
</tr> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
929번째 줄: | 908번째 줄: | ||
이제 <code>TaskController</code>에 <code>destroy</code> 메소드를 정의할 준비가 거의 끝났습니다. 먼저, 이 라우트에 대한 라우트 선언과 컨트롤러 메소드를 다시 확인해봅시다: | 이제 <code>TaskController</code>에 <code>destroy</code> 메소드를 정의할 준비가 거의 끝났습니다. 먼저, 이 라우트에 대한 라우트 선언과 컨트롤러 메소드를 다시 확인해봅시다: | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
Route::delete('/task/{task}', 'TaskController@destroy'); | |||
/** | |||
* 주어진 태스크를 삭제합니다. | |||
* | |||
* @param Request $request | |||
* @param Task $task | |||
* @return Response | |||
*/ | |||
public function destroy(Request $request, Task $task) | |||
{ | { | ||
// | |||
/ | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
973번째 줄: | 936번째 줄: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
다음으로, 정책에 <code> | 다음으로, 정책에 <code>destroy</code> 메소드를 추가해보겠습니다. 이 메소드는 <code>User</code> 인스턴스와 <code>Task</code> 인스턴스를 받습니다. 메소드는 단순히 사용자의 ID가 태스크의 <code>user_id</code>와 일치하는지 확인합니다. 실제로 모든 정책 메소드는 <code>true</code> 또는 <code>false</code>를 반환해야 합니다: | ||
<syntaxhighlight lang='php'> | <syntaxhighlight lang='php'> | ||
<?php | <?php | ||
983번째 줄: | 945번째 줄: | ||
use App\Models\User; | use App\Models\User; | ||
use App\Models\Task; | use App\Models\Task; | ||
use Illuminate\Auth\Access\HandlesAuthorization; | |||
class TaskPolicy | class TaskPolicy | ||
{ | { | ||
use HandlesAuthorization; | |||
/** | /** | ||
* | * 주어진 사용자가 주어진 태스크를 삭제할 수 있는지 결정합니다. | ||
* | * | ||
* @param User $user | * @param User $user | ||
993번째 줄: | 958번째 줄: | ||
* @return bool | * @return bool | ||
*/ | */ | ||
public function | public function destroy(User $user, Task $task) | ||
{ | { | ||
return $user->id === $task->user_id; | return $user->id === $task->user_id; | ||
1,000번째 줄: | 965번째 줄: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
마지막으로, <code>Task</code> 모델을 <code>TaskPolicy</code>와 연계해야 합니다. 이는 <code>app/Providers/AuthServiceProvider.php</code> 파일의 <code>$policies</code> 속성에 한 줄을 추가하여 수행할 수 있습니다. 이를 통해 Laravel은 <code>Task</code> 인스턴스에서 태스크를 인증할 때 어떤 정책을 사용할지 알 수 있습니다: | |||
< | |||
< | |||
<syntaxhighlight lang='php'> | |||
/** | |||
* 애플리케이션의 정책 매핑. | |||
* | |||
* @var array | |||
*/ | |||
protected $policies = [ | |||
'App\Models\Task' => 'App\Policies\TaskPolicy', | |||
]; | |||
</syntaxhighlight> | |||
;액션 인가 | |||
정책이 작성되었으므로, 이를 <code>destroy</code> 메소드에서 사용해 보겠습니다. 모든 Laravel 컨트롤러는 <code>AuthorizesRequest</code> 트레이트를 통해 노출된 authorize 메소드를 호출할 수 있습니다: | |||
<syntaxhighlight lang='php'> | |||
/** | |||
* 주어진 태스크를 삭제합니다. | |||
* | |||
* @param Request $request | |||
* @param Task $task | |||
* @return Response | |||
*/ | |||
public function destroy(Request $request, Task $task) | |||
{ | { | ||
$this->authorize('destroy', $task); | |||
// 태스크를 삭제합니다... | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
1,041번째 줄: | 1,006번째 줄: | ||
마지막으로, 주어진 태스크를 실제로 삭제하는 로직을 <code>destroy</code> 메소드에 추가해 보겠습니다. Eloquent의 <code>delete</code> 메소드를 사용하여 데이터베이스에서 주어진 모델 인스턴스를 삭제할 수 있습니다. 레코드가 삭제된 후, 사용자를 <code>/tasks</code> URL로 리디렉션할 것입니다: | 마지막으로, 주어진 태스크를 실제로 삭제하는 로직을 <code>destroy</code> 메소드에 추가해 보겠습니다. Eloquent의 <code>delete</code> 메소드를 사용하여 데이터베이스에서 주어진 모델 인스턴스를 삭제할 수 있습니다. 레코드가 삭제된 후, 사용자를 <code>/tasks</code> URL로 리디렉션할 것입니다: | ||
<syntaxhighlight lang='php | <syntaxhighlight lang='php'> | ||
/** | |||
* 주어진 태스크를 삭제합니다. | |||
* | |||
* @param Request $request | |||
* @param Task $task | |||
* @return Response | |||
*/ | |||
public function destroy(Request $request, Task $task) | |||
{ | |||
$this->authorize('destroy', $task); | |||
$task->delete(); | |||
return redirect('/tasks'); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> |