Page 1


6

목차

01

1.1 _ 모델-뷰-컨트롤러 패턴

16

1.2 _ 유연한 데이터베이스 지원

20

1.3 _ 보안을 고려한 설계

21

1.4 _ 가볍고 익히기 쉬운 템플릿 엔진

25

1.5 _ 간편 URL

26

1.6 _ 컴포넌트 기반의 확장성

27

1.7 _ 의존성 주입과 제어 역전

27

1.8 _ 설정보다 관례 패러다임

31

1.9 _ 우아한 문법과 코딩 표준

32

1.10 _ 국제화 지원

34

1.11 _ 손쉬운 테스트

36

정리

37

02

2.1 _ 가상 머신과 Vagrant 설치

39

개발 환경 구축

2.2 _ 홈스테드 구성

라라벨 소개

Vagrant란?

39

Vagrant 설치

42

45

라라벨 박스 생성

45

환경 구성

47

박스 구동 및 중지

52

2.3 _ 데이터베이스 설정

55

2.4 _ Nginx와 php-fpm 재시작

58

2.5 _ HTTP 개요

59

HTTP 이해의 필요성

59

피들러 설치

60

HTTP 통신 엿보기

63

HTTP 요청 엿보기

65

HTTP 응답 엿보기

67


목차

03

라라벨과의 만남

04

명령행, 컨트롤러, 고급 라우팅

2.6 _ 가상 호스트의 추가 및 변경

70

정리

73

3.1 _ 라라벨 프로젝트 만들기

75

라라벨 설치

75

환경 구성

81

url

84

3.2 _ 라라벨 디렉터리 구성

85

3.3 _ URL 라우팅

86

3.4 _ HTTP 응답 처리

92

3.5 _ 뷰

96

3.6 _ 블레이드 템플릿

101

변수 출력

101

제어문

105

레이아웃과 상속

108

블레이드 디버깅

111

정리

113

4.1 _ 서비스 프로바이더와 파사드

114

서비스 프로바이더

114

파사드

116

라라벨 패키지 설치

118

4.2 _ HTTP 예외 처리

119

4.3 _ artisan

121

애플리케이션을 정비 모드로 전환하기

123

단독 실행 서버 구동하기

124

atrisan을 이용한 모델 생성

125

tinker를 이용한 대화형 디버깅

126

7


8

목차

4.4 _ 컨트롤러

130

기본 컨트롤러와 라우트

130

암시적 컨트롤러

139

RESTful 리소스 컨트롤러

141

tinker를 이용한 컨트롤러 테스트

142

4.5 _ 미들웨어 미들웨어란?

143 143

정리

149

05

5.1 _ 데이터베이스 마이그레이션

150

마이그레이션과 시딩

5.2 _ 데이터베이스 시딩

마이그레이션 생성

151

스키마 빌더

153

시드 생성

5.3 _ 모델 팩토리

06

컬렉션

163 163

167

모델 팩토리 생성

169

Persistence 데이터 생성

170

정리

171

6.1 _ 컬렉션 생성

173

6.2 _ 주요 컬렉션 메서드

174

정리

183


목차

07

7.1 _ 관례

엘로퀀트 ORM

7.2 _ CRUD 실행하기

185

테이블과 모델명

185

데이터베이스 연결 정보

186

189

모델 검색하기(Read)

189

모든 데이터 읽기

189

모델 입력과 갱신(Create/Update)

199

대량 할당 예외 처리

202

모델 삭제(Delete)

205

7.3 _ 쿼리 스코프

210

쿼리 스코프 추가

211

동적 쿼리 스코프

212

7.4 _ 모델 이벤트

213

7.5 _ 접근자와 변경자

218

7.6 _ 테이블 관계

221

일대일 관계

222

일대다 관계

223

다대다 관계

227

연결을 통한 다수 관계

234

다형성 관계

235

7.7 _ 연관 모델 삽입

242

참조키 자동 삽입

242

포함 관계 갱신

243

다대다 관계 삽입

245

부모 모델의 타임스탬프 갱신

247

7.8 _ 연관 모델 삭제

248

삭제 시 단계적으로 삭제

249

자식 객체를 삭제한 후 부모 객체 삭제

249

모델 이벤트로 처리

250

정리

250

9


10

목차

08

일정 관리 서비스 만들기

09

사용자 등록과 로그인

10

프로젝트와 태스크 등록하기

8.1 _ 서비스 개요

252

8.2 _ 프로젝트 생성

253

8.3 _ 스키마 설계와 마이그레이션

257

8.4 _ 화면 설계

263

8.5 _ 메시지 지역화

274

8.6 _ 외부 패키지를 이용한 기능 확장

276

패키지 저장소

276

라라벨 패키지 설치

277

정리

280

9.1 _ 아이디와 비밀번호를 이용한 인증

281

9.2 _ 사용자 계정 등록 페이지

288

9.3 _ 깃허브를 통한 인증

290

9.4 _ 세션

299

세션 설정

299

세션 사용

302

정리

304

10.1 _ 스캐폴딩 생성 및 관계 설정

305

컨트롤러와 모델 생성

306

모델 간 관계 설정

307

데이터 시딩

309

10.2 _ 리소스 컨트롤러와 라우팅

313

컨트롤러 등록

313

인증 미들웨어 연결

314

중첩 리소스

315


목차

10.3 _ 프로젝트 기능 구현

316

인덱스 구현

316

show 구현

320

디버그바를 이용한 디버깅

322

프로젝트 편집 기능 구현과 CSRF/메서드 스푸핑

324

생성 기능 구현

330

삭제 구현

332

10.4 _ 할일 기능 구현

334

프로젝트별 태스크 인덱스

334

수정 기능 구현

338

태스크 생성 기능 구현

343

10.5 _ 메인 화면 구현

347

10.6 _ 비중첩 Task 컨트롤러

348

검색 기능 구현

354

10.7 _ 로깅

358

정리

359

11

11.1 _ 즉시 로딩

360

서비스 개선

11.2 _ 리소스 권한 검사 미들웨어

364

11.3 _ 페이지 처리

366

11.4 _ 데이터 검증하기

369

컨트롤러에서 처리

369

폼 요청 검증

372

검증 규칙

373

사용자 정의 검증 규칙

375

정리

379

N+1 문제

361

즉시 로딩

362

11


12

목차

12

12.1 _ 이메일

외부 서비스와의 연계

12.2 _ 비밀번호 재설정

387

12.3 _ 주기적으로 만료 기한 통보하기

391

13

라라벨 배포

14

PHP 5의 특징

380

메일 드라이버 설정

381

이메일 전송

384

cron 설정

391

artisan 명령어 작성

392

스케줄러 설정

395

12.4 _ 레디스와의 연동

397

레디스 맛보기

398

세션 교체

400

카운팅 적용

401

정리

406

13.1 _ 배포 환경 선택

407

13.2 _ 우분투 서버에 배포

408

서버 설정

408

애플리케이션 배포

414

13.3 _ AWS EC2에 배포

418

정리

424

14.1 _ 네임스페이스

427

14.2 _ 간결한 배열

433

14.3 _ 트레이트

434

14.4 _ 클래스 자동 로딩

437

14.5 _ 익명 함수

438

14.6 _ 동적 프로퍼티/메서드 생성

440


목차

14.7 _ ::class 키워드를 이용한 클래스 이름 결정

443

14.8 _ 타입 힌팅

444

14.9 _ PHP 표준 권고(PSR)

446

15

15.1 _ 프로젝트를 수행할 때 겪는 문제들

451

컴포저

15.2 _ 유의적 버전

453

15.3 _ 컴포저의 해결책

454

15.4 _ 컴포저를 이용한 의존성 관리

455

15.5 _ 의존 패키지의 버전 지정

460

15.6 _ 프로젝트 참여자의 의존성 일치시키기

462

15.7 _ 자동로더

464

라이브러리 설치 관리 문제

451

의존성 지옥

452

13


01 라라벨 소개

라라벨은 PHP를 기반으로 하는 웹 개발 프레임워크로서, 테일러 오트웰( Taylor Otwell)과 커뮤니 티의 회원에 의해 개발됐습니다. 공식 홈페이지는 www.laravel.com이고 깃허브( https://github.

com/laravel/laravel)를 통해 개발이 진행되고 있습니다. MIT 라이선스를 채택했으므로 상업적인 이용에 제한이 없고 결과물에 대해 소스를 공개하지 않아도 됩니다. 원작자인 테일러 오트웰은 라라벨 2.0 버전을 발표하면서 “PHP 개발자가 스파게티 코드에서 벗어날 수 있도록 하겠다”는 목표를 밝혔습니다. 실제로 라라벨은 현대적인 PHP의 기능을 최대한 활용해 아 름답고 우아하게 코드를 작성할 수 있으며, 다양하고 풍부하고 사용하기 쉬운 기능을 제공하므로 최 소한의 코딩으로 강력하고 견고한 웹 애플리케이션을 개발할 수 있습니다. 이제는 라라벨 프레임워크의 장점이 많이 알려져서 나날이 사용자가 늘고 있으며, 해외에서는 가장 사용자가 많은 PHP 프레임워크로 자리 잡고 있으며 구글 트렌드( http://goo.gl/B9CU7k)를 보면 엄청난 성장세를 보이고 있음을 알 수 있습니다.


01 _ 라라벨 소개

[그림 1.1] PHP 프레임워크 트렌드

그림 1.2 깃허브 관심도

라라벨은 PHP 프레임워크 분야에서 압도적인 점유율을 보이고 있으며, 레일즈나 장고 못지 않은 높 은 인기를 누리고 있습니다.

15


16

쉽게 배우는 라라벨 5 프로그래밍

[그림 1.3] 레일즈/장고와의 비교

라라벨은 루비 온 레일스( ruby on rails), ASP.NET MVC, 루비의 마이크로 프레임워크인 시나트라 ( Sinatra)에서 많은 영향을 받았습니다. 라라벨을 사용하다 보면 라라벨이 다른 프레임워크의 장점을 많이 흡수하려고 노력했다는 느낌을 많이 받을 것입니다. 그럼 이제부터 라라벨 프레임워크의 장점에 대해 간략하게 살펴보겠습니다.

1.1 _ 모델-뷰-컨트롤러 패턴 MVC( Model View Controller)는 비즈니스 로직과 사용자 뷰 영역을 분리하기 위한 소프트웨어 개 발 패턴입니다. 과거의 PHP 개발은 MVC를 따르지 않고 한 파일에 모든 로직을 기술하는 형식으로 진행되는 경우가 많았습니다. 예를 들어, 다음은 GET 매개변수에 따라 직원 데이터베이스에서 직원을 검색하거나 삭제하는 PHP 예제입니다.


01 _ 라라벨 소개

[예제 1.1] MVC 미적용 코드

<?php $con = mysql_connect("localhost", "laravel", "homestead"); if (!$con) { die('Could not connect: ' . mysql_error()); } $mode = $_GET["mode"]; if ($mode == "list") { mysql_select_db("laravel", $con); $result = mysql_query("SELECT * FROM users"); echo "<table border='1'> <tr> <th>user_id</th> <th>user_name</th> <th>email</th> </tr>"; while ($row = mysql_fetch_array($result)) { echo "<tr>"; echo "<td>" . $row['id'] . "</td>"; echo "<td>" . $row['name'] . "</td>"; echo "<td>" . $row['email'] . "</td>"; echo "</tr>"; echo "\r\n"; } echo "</table>"; } else if ($mode == "delete") { $result = mysql_query("DELETE FROM users where id = " .

$_GET["user_id"]);

echo "delete done!"; } mysql_close($con); ?>

위 코드는 $mode의 값의 설정 여부에 따라 다른 동작을 하며, 비즈니스 로직과 데이터베이스에서 가 져온 모델, 그리고 처리 결과를 보여주는 뷰 로직이 하나의 파일에 작성돼 있습니다. 이 경우 소프트 웨어의 규모가 증가할수록 복잡도가 늘어나고 수정하기가 어려워지며, 문제가 발생할 경우 디버깅도 매우 힘들어집니다.

17


18

쉽게 배우는 라라벨 5 프로그래밍

비즈니스 로직을 구현한 애플리케이션 코드와 이를 사용자에게 전달하기 위한 화면 디자인은 필요 한 기술과 능력이 서로 다르므로 각 분야의 전문가가 분업하는 것이 품질과 효율성 측면에서 효과적 입니다. 규모가 있는 프로젝트이면 개발자와 디자이너가 별도로 존재하기 마련입니다. 그런데 한 파일에 비즈 니스 로직과 화면 디자인이 함께 들어있다면 디자이너가 화면의 디자인을 변경하려면 개발자의 도움 이 필요하고, 개발자가 코드를 수정하려면 디자이너의 도움이 받아야 하는 등 작업 효율이 떨어지고, 자신의 전문 분야가 아닌 부분을 건드려야 하므로 품질도 떨어질 우려가 있습니다.

[그림 1.4] MVC가 적용되지 않은 경우

대부분의 웹 프레임워크가 기본적으로 MVC 패턴을 지원하고 있듯이 라라벨에서도 MVC를 지원하 고 있으며, 라라벨 MVC는 가볍고 사용하기 쉽고 유연하므로 비즈니스 로직과 디자인을 분리함으로 써 간결하고 우아하고 유지보수가 쉬운 코드를 작성할 수 있습니다.

[그림 1.5] MVC 패턴


01 _ 라라벨 소개

다음은 앞에서 살펴본 코드를 라라벨 MVC를 활용해 구현한 예제입니다. 컨트롤러에서 모델을 생성 하고 이를 뷰에 전달함으로써 코드가 간결하고 우아하며, 기능이 분리되므로 코드 작성이 쉽고 유지 보수가 쉬우리라는 것을 짐작할 수 있습니다. [예제 1.2] 사용자 관련 로직을 처리하는 컨트롤러

<?php namespace App\Http\Controllers; class UserController extends Controller { // 사용자 목록 보기 public function list() { $list = User::findAll(); return view('user.list')->with('list', $list); } // 사용자 삭제 public function delete($id) { User::delete($id); return view('user.delete'); } }

[예제 1.3] 사용자 목록을 보여주는 뷰

<html> <body> <h1>User List</h1> <?php foreach ($list as $u): ?> <li><?php echo $u['name']; ?> </li> <?php endforeach; ?> </body> </html>

19


20

쉽게 배우는 라라벨 5 프로그래밍

1.2 _ 유연한 데이터베이스 지원 데이터베이스 추상화 웹 개발 환경에서 데이터베이스는 굉장히 중요한 요소이며, PHP는 MySQL, PostgreSQL, SQLite,

MS-SQL Server, Oracle, Cubrid 등 다양한 DBMS를 지원하고 있습니다. 라라벨은 자바의 JDBC처럼 데이터베이스 레이어를 추상화한 PDO( PHP Data Objects)를 사용하 므로 mysql_fetch_array나 oci_fetch_array처럼 특정 벤더에 의존적인 함수를 사용하지 않고도 데 이터베이스 관련 코드를 작성할 수 있습니다. 또한 의존성 주입을 사용해 런타임에 사용할 데이터베이스를 결정하므로 설정을 변경하는 것만으로 사용 중인 DBMS의 종류를 변경할 수 있습니다. 라라벨 5는 공식적으로 MySQL, PostgreSQL, SQLite, MS-SQL Server의 4가지 DBMS만 지원하며, 그 밖의 데이 터베이스는 커뮤니티에서 작성한 것을 사용해야 합니다.

[그림 1.6] 데이터베이스 추상화

쿼리 빌더와 ORM 지원 라라벨은 쿼리 빌더( Query Builder) 기능을 제공하므로 이를 이용하면 SQL을 사용하지 않고도 손 쉽게 데이터베이스 작업을 처리할 수 있습니다. 다음은 고객 테이블에서 특정 이메일 주소를 가진 고객 정보를 가져온 후 이메일 인증 여부 필드를

true로 설정하는 예제입니다.


01 _ 라라벨 소개

DB::table('customers') ->where('email', 'user@example.com') ->update(['confirmed' => true]);

라라벨은 루비 온 레일스( Ruby on Rails) 프레임워크의 액티브 레코드( Active Record)와 동일한 역할을 수행하는 엘로퀀트( Eloquent)라는 ORM을 통해 PHP 모델 클래스와 데이터베이스 테이블 을 손쉽게 연계할 수 있으며, SQL 구문 없이 데이터 간의 다양한 관계를 표현할 수 있으므로 특정

DBMS에 의존적이지 않으며, 데이터베이스의 칼럼 추가/수정/삭제 등 변경이 발생해도 코드 수정을 최소화할 수 있습니다.

[그림 1.7] 엘로퀀트 ORM

1.3 _ 보안을 고려한 설계 이제 보안은 “하면 좋고 안 해도 그만”인 요소가 아니라 고객과 비즈니스를 보호하기 위해 필수적으 로 고려해야 하는 부분 중 하나가 됐습니다. 그리고 이를 위해 개발팀에서 우선적으로 고려해야 할 사 항이 바로 시큐어 코딩( secure coding)입니다. 하지만 시큐어 코딩은 보안에 대한 일정 수준의 이해 를 필요하며, 바쁜 프로젝트 일정상 이를 고려하지 않고 개발되는 경우가 많은 것이 사실입니다. 라라벨은 프레임워크 차원에서 보안을 위해 여러 가지 기능을 제공하고 있으므로 주요 취약점에 대해 어렵지 않게 대응할 수 있습니다.

21


22

쉽게 배우는 라라벨 5 프로그래밍

public 폴더 노출 최소화 및 설정 파일 숨김 기존의 PHP 웹 애플리케이션은 애플리케이션 구조가 파일 시스템과 일치하는 경우가 많았고, 이로 인해 웹 애플리케이션 구동에 필요한 설정 파일(데이터베이스 연결 정보, 파일 경로 등)도 웹 서버에 두는 경우가 많았습니다. 예를 들어, 다음과 같이 데이터베이스 연결 정보가 담긴 설정 파일을 require로 가져와서 데이터베이 스에 연결하는 경우를 생각해 봅시다. <?php require_once('conf/db_conn.inc'); connect_db(); ?>

이 경우 브라우저에서 example.com/conf/db_conn.inc를 바로 호출하면 데이터베이스 계정 정 보가 노출되고, 이를 통해 고객 정보가 유출되는 보안 사고가 발생할 위험이 있습니다. 이처럼 직접

URL을 입력하는 공격 방식을 강제 브라우징( forced browsing)이라고 합니다. 이를 막기 위해서는 웹 서버가 특정 확장자(예: .inc, .htaccess)가 지정된 파일은 서비스하지 않도록 별도의 보안 설정을 하거나 웹 서버의 DocumentRoot 이외의 경로에 db_conn.inc를 두고 애플리케이션에서 절대 경로 로 읽어들여야 합니다. 이러한 보안 취약점이 발생할 여지를 차단하고자 라라벨은 구동에 필요한 설정 파일을 웹 서버의

DocumentRoot와 격리했으므로 설정 파일 유출에 따른 보안 문제를 최소화합니다. 또한 .php의 직접 호출이 아닌 애플리케이션 라우팅을 통해 서비스를 제공하도록 설계됐고, public 폴더에는 단 하나의 PHP( index.php) 파일만 존재합니다. 이를 통해 public 폴더의 노출을 최소화 했고 .php 파일의 직접 호출을 통한 공격이나 설정 파일을 브라우저에서 내려받을 수 있는 취약점의 발생 가능성을 최소화했습니다.

SQL 삽입 공격 만약 사용자 아이디와 암호를 입력받아 로그인을 처리하는 페이지에서 SQL 삽입( SQL Injection) 공 격을 고려하지 않는다면 다음과 같이 코드를 작성할 것입니다.


01 _ 라라벨 소개

[예제 1.4] SQL 삽입 공격 취약 코드

$sql="SELECT * FROM users WHERE userid='$userid' and password='$password'"; $result=mysql_query($sql); $count=mysql_num_rows($result); if($count==1){ //login 성공 } else { //login 실패 }

PHP 7에서는 mysql 확장이 삭제됐으므로 mysql_*로 시작하는 함수를 더는 사용할 수 없으며, 대신 mysqli나 pdo_ mysql을 사용해야 합니다.

위와 같은 코드는 클라이언트가 보낸 문자열을 검증 없이 사용하므로 공격자가 password에 aaa’ or ‘1’ = ‘1라는 문자열을 넣으면 or 뒤의 문장이 참이므로 아이디와 암호를 몰라도 관리자로 로그인할 수 있게 됩니다.

[그림 1.8] SQL 삽입 공격

23


24

쉽게 배우는 라라벨 5 프로그래밍

이를 막기 위해 라라벨에서는 모든 매개변수를 문자열로 처리하지 않고 PDO 변수에 바인딩해서 처 리하므로 대부분의 SQL 삽입 공격을 방지할 수 있습니다. 라라벨의 DB 기능을 사용해 사용자의 아이디와 암호를 조회하기 위해 다음과 같이 코드를 작성했다 고 가정해 보겠습니다. DB::select('select * from users where id = :userid and password = :password', ['userid' => 'myid', 'password' => 'mypasswd']);

라라벨에서 데이터베이스 쿼리를 생성하는 기능을 제공하는 쿼리 빌더는 매개변수를 내부적으로 준 비된 문장( Prepared Statement)과 매개변수 바인딩( Bound Parameter)을 통해 다음과 같이 안전 하게 SQL을 실행합니다. $s = $dbh->prepare('SELECT * FROM users WHERE userid = :userid and password = :password') ; $s->bindParam(':userid ', $userid ); $s->bindParam(':password', $password);

이제 공격자가 SQL 삽입 공격을 시도해도 입력한 문자는 이미 해석이 끝난 SQL 문에 매개변수로 전 달되므로 aaa’ or ‘1’ = ‘1을 입력해도 password 칼럼의 값이 aaa’ or ‘1’=’1’인 레코드를 찾게 되므로 개발자가 특별히 신경 쓰지 않아도 기본적으로 SQL 삽입 공격을 방지할 수 있습니다. 그리고 사이트 간 스트립팅( CSS 또는 XSS( Cross-site Scripting)) 공격을 막기 위해 뷰 단에 출력 하는 데이터는 htmlentities() 함수로 변환하고 있으며(3.6절 블레이드 템플릿에서 설명합니다.) 웹 애플리케이션의 가장 취약한 부분 중 하나인 사이트 간 요청 위조( CSRF; Cross-site Request

Forgery)를 막기 위해 기본적으로 POST, DELETE, PUT 같이 서버의 데이터를 수정하거나 삭제할 가능성이 있는 액션에는 CSRF 토큰을 삽입하고 검증하고 있습니다. 이는 라라벨의 기본 기능이므로 애플리케이션 개발자는 VIEW 단에 CSRF를 출력하는 메서드인

csrf_token();만 추가하면 서버 측에서 별도의 CSRF 검증 코드를 구현하지 않아도 CSRF 공격에 견 고한 서비스를 만들 수 있습니다. 또한 세션을 가로채서 공격하는 HTTP 세션 하이재킹( HTTP Session Hijacking)을 막기 위해 모든 세션 데이터는 강력한 알고리즘으로 암호화(9.4 세션 참고)되어 저장됩니다. 라라벨이 제공하는 보안 기능에 대해서는 후반부의 실전 프로젝트를 구현할 때 자세히 살펴보겠습 니다.


01 _ 라라벨 소개

1.4 _ 가볍고 익히기 쉬운 템플릿 엔진 PHP로 웹 개발을 할 경우 뷰 레이어 코드를 작성할 때 HTML에<?php echo $val; ?>와 같이 데이 터를 출력하는 코드를 넣는 것은 매우 귀찮고 실수할 여지가 많은 작업이었습니다. 라라벨은 블레이드( blade)라는 단순하고 사용하기 쉬운 템플릿 엔진을 내장하고 있으므로 뷰 코드를 작성할 때 이런 수고를 더는 하지 않고도 MVC 패러다임에 맞춰 개발할 수 있습니다.

[그림 1.9] 템플릿 엔진

블레이드는 상속을 지원하므로 레이아웃이나 jQuery를 포함하는 <script> 구문 같이 페이지마다 공 통적으로 사용하는 부분은 상속을 통해 체계적으로 관리할 수 있습니다.

25


26

쉽게 배우는 라라벨 5 프로그래밍

블레이드 템플릿을 사용하면 HTML과 CSS를 바로 사용하고, PHP 구문만 특정 태그로 처리하면 되 므로 디자이너와 개발자 간의 협업도 더욱 쉬워집니다. 블레이드의 또 다른 장점 중 하나는 뷰 레이어에 출력하기 위해 {{ }}를 호출하면 e()라는 도우미 함수 로 변환되고, 도우미 함수 내부에서 htmlspecialchars() 호출을 통해 위험한 특수 문자열을 자동으 로 변환해 준다는 점입니다. 그러므로 뷰에 출력할 때마다 직접 htmlspecialchars()로 필터링할 필 요가 없어지므로 코드의 양이 줄어들고 혹시 모를 실수로 인해 XSS 공격을 당할 위험이 줄어듭니다.

1.5 _ 간편 URL PHP 기반으로 웹 서비스를 제공할 경우 실제 파일 시스템과 웹 서비스의 URL이 일치하도록 제 공하는 경우가 많았습니다. 그래서 웹 서비스의 소스 디렉터리( DocumentRoot)가 /var/www/

example.com이고 다음과 같은 디렉터리를 만든 후 웹 브라우저에서 http://example.com/cart/ view.php를 호출할 경우 /var/www/example.com/cart/view.php를 실행한 결과가 브라우저에 전송됩니다. . ├── ./item │

└── ./show.php

└── ./user ├── ./user/login.php └── ./user/regist.php

파일 시스템의 소스 파일이 서비스의 라우팅과 일치했으므로 “http://example.com/item/show.

php”가 서비스 URL처럼 사용됐으며, 매개변수가 필요할 경우 URL에 GET 방식의 매개변수를 전달 했습니다. 예를 들어, 카테고리가 8번인 품목을 가격으로 정렬해서 표시할 경우 다음과 같은 URL 구 조를 사용했습니다. http://example.com/item/show.php?category=8&orderby=price

위과 같이 구현하면 웹 서비스가 파일 시스템에 종속되고 URL을 변경하려면 소스의 폴더 구조를 변 경해야 합니다. 또한 매개변수가 있을 경우 URL을 기억하기가 어려워져서 사용자의 웹 접근성이 떨 어지는 문제가 있습니다.


01 _ 라라벨 소개

간편( clean ) URL 은 Pretty URL , 사용자 친화적( User Friendly ) URL 이라고도 하며 http ://

example.com/item/category/8/show/orderby/price처럼 사용자가 기억하기 쉽고 의미 있으며 파일 시스템과 분리된 URL로 서비스를 제공하는 것을 의미합니다. 라라벨을 이용하면 간단하게 간편

URL 기반의 웹 서비스를 만들 수 있습니다.

1.6 _ 컴포넌트 기반의 확장성 라라벨 프레임워크는 컴포넌트 기반으로 기능을 확장할 수 있으므로 원하는 기능이 없을 경우 사용자 는 컴포넌트를 이용해 손쉽게 기능을 확장할 수 있습니다. 또한 기존 PHP 코드가 있다면 기존 코드 를 크게 변경하지 않고도 이를 라라벨 패키지로 재작성할 수 있습니다. 라라벨은 프레임워크의 코어와 패키지가 분리돼 있으므로 외부에서 만든 패키지를 탑재할 수 있으며, 특히 컴포저를 지원하는 패키지라면 간단하게 한 줄의 명령어로 손쉽게 외부 패키지를 사용할 수 있 습니다. 예를 들어, 다음은 라라벨에서 엑셀 파일을 다룰 수 있는 패키지를 설치하는 명령어입니다. $ composer require "maatwebsite/excel" "~2.0.0"

실제로 라라벨에서 제공하는 여러 패키지는 심포니 프레임워크에서 제공하는 기능을 확장하거나 또 는 그대로 차용한 것이 많습니다. http://symfony.com/projects/laravel에서 라라벨이 사용하는 심포니 프레임워크의 컴포넌트를 확인할 수 있습니 다.

라라벨은 패키지 관리자로 컴포저를 사용하므로 손쉽게 패키지 간 의존성 관리를 할 수 있으며,

http://packagist.org 같은 온라인 PHP 패키지 저장소에서 손쉽게 패키지를 검색하거나 설치할 수 있습니다. 컴포저에 대한 자세한 내용은 “부록 2 컴포저“ 항목을 참고하세요.

1.7 _ 의존성 주입과 제어 역전 의존성 주입( DI; Dependency injection)과 제어 역전( IoC; Inversion of Control)은 모듈 간의 의존성을 줄이고 소스코드 수정 없이 런타임에 더욱 유연한 소프트웨어를 만들 수 있는 개발 패턴 입니다.

27


28

쉽게 배우는 라라벨 5 프로그래밍

먼저 의존성 주입은 객체지향 언어에서 제공하는 인터페이스( Interface)를 활용해 구현됩니다. 예를 들어, 사용자의 정보를 저장하고 읽어오는 UserRepository 클래스가 있고, 이 안에는 저장소에서 사 용자의 정보를 처리하는 $repository라는 변수가 있다고 해봅시다. 서비스 초기이고 사용자가 적어서 사용자 정보를 콤마로 구분된 CSV 파일로부터 읽어들이기로 했습 니다. 물론 향후 확장성을 위해 RepositoryInterface라는 인터페이스를 만들었고, CSVRepository 는 이를 구현한 클래스입니다. <?php class UserRepository implements RepositoryInterface { private $repository; public function __construct() { $this->repository = new CSVRepository; } }

이제 서비스 코드에서는 다음과 같이 인터페이스를 구현한 클래스의 인스턴스를 생성한 후 사용하게 합니다. // 저장소 생성 및 사용 RepositoryInterface $repos = new UserRepository(); $repos->store();

시간이 지나 서비스 사용자가 많아지자 사용자 정보를 MySQL에서 처리하기로 하고 관련 로직을 구 현했습니다. 그리고 UserRepository를 다음과 같이 수정합니다. <?php class MySQLUserRepository implements RepositoryInterface { private $repository; public function __construct() { $this->repository = new MySQLRepository; } }


01 _ 라라벨 소개

// 저장소 생성 및 사용 RepositoryInterface $repos = new MySQLUserRepository(); $repos->store();

그런데 서비스 사용자가 더욱 많아지고 성능 개선을 위해 저장소를 레디스( Redis) 키/값 저장소로 변 경하기로 했습니다. 인터페이스를 잘 설계하고 이를 구현했다면 위와 같은 상황에서 RedisUserRepository 클래스를 구 현하고 기존 서비스의 인스턴스 생성 코드를 수정해서 대처할 수 있습니다. <?php class RedisUserRepository implements RepositoryInterface { private $repository; public function __construct() { $this->repository = new RedisRepository; } }

하지만 외부에서 이 제품을 사용하겠다는 곳이 두 곳이 나타났는데 각각 DBMS를 MS-SQL과

PostgreSQL을 사용한다고 합니다. 사용자 저장소를 인터페이스로 만들었지만 실제 서비스 코드에서 는 인터페이스를 구현한 코드가 들어가야 하며 고객이 사용하는 DBMS에 따라 제품을 나눌 경우 버 전 관리가 매우 힘들어지며 새로운 DBMS가 추가될 경우 인스턴스를 생성하는 코드도 계속 수정해야 합니다. <?php class MSSQLUserRepository implements RepositoryInterface { private $repository; public function __construct() { $this->repository = new MSSQLRepository; } }

29


30

쉽게 배우는 라라벨 5 프로그래밍

// repository 생성 및 사용 RepositoryInterface $repos = new MSSQLUserRepository(); $repos->store();

하지만 의존성 주입과 제어의 역전 기술을 이용하면 인터페이스를 사용하는 코드를 수정하지 않고도 런타임에 의존성을 결정할 수 있습니다. [예제 1.5] 의존성 주입 적용

<?php class UserRepository implements RepositoryInterface { private $repository; public function __construct(RepositoryInterface $repository) { $this->repository = $repository; } }

이제 의존성 제어 처리 로직에서 설정 파일이나 옵션에서 RepositoryInterface를 구현한 인터페이스 를 생성해 UserRepository에 주입하면 다른 저장소를 사용하는 곳이 나타나도 코드를 수정하지 않 고도 설정만으로 처리할 수 있습니다. $repos = App:make('UserRepository'); // $repos 사용

위와 같은 기법을 의존성 주입( DI; Dependency Injection)이라고 하며, 외부에서 의존성이 주입되 므로 이런 제어를 제어의 역전( IOC; Inversion of Control)이라고 합니다. 의존성 주입은 일반적인 서비스나 애플리케이션에서는 고려하지 않아도 되는 경우가 많지만 외부 환경에서 구동해야 하는 제 품(솔루션, 프레임워크)에서는 도입을 고려해 봐야 하는 기능입니다. 의존성을 주입하는 방법은 위에서 설명한 생성자를 이용하는 방법과 세터( setter)를 이용하는 방법이 있으며, 라라벨은 전자를 사용하고 있습니다. 라라벨은 많은 부분을 런타임에 의존성을 주입하고 있으며 주입할 의존성 인터페이스는 타입 힌트를 통해 결정하고 있습니다. 또한 의존성 인터페이스를 구체적으로 구현한 프로바이더는 보통 설정 파일 에서 읽어오므로 설정 파일의 내용만 변경하면 애플리케이션을 수정하지 않고도 유연하게 패키지를 사용할 수 있습니다.


01 _ 라라벨 소개

예를 들어, config/session.php에 들어있는 세션 드라이버 설정을 다음과 같이 한 줄만 바꾸면 캐시 데이터 저장소를 파일 시스템에서 DBMS로, 또는 레디스나 멤캐시( memcache) 같은 키/값 저장소 로 변경할 수 있습니다. // 파일 세션 드라이버에서 레디스로 변경 //'driver' => env('SESSION_DRIVER', 'file') 'driver' => env('SESSION_DRIVER', 'redis')

1.8 _ 설정보다 관례 패러다임 설정보다 관례( CoC; Convention over Configuration)는 소프트웨어 개발자가 정해야 하는 수많 은 결정을 줄이고 단순함을 확보하면서도 유연함을 잃지 않기 위한 설계 패러다임입니다. 프레임워크가 복잡해지고 기능이 방대해지면서 수많은 설정 파일과 설정의 부담이 생겨났습니다.

CoC는 이러한 문제점을 해결하기 위해 자주 사용하는 부분은 관례를 정해서 생략하고 이를 따르지 않을 경우에만 설정하도록 도와줍니다. 여러 현대적인 프레임워크(스프링 프레임워크, 루비온레일스, 심포니 등)가 CoC 패러다임을 따르고 있으며, 라라벨도 이러한 CoC 패러다임에 입각해서 설계되어 라라벨에서 제공하는 기능들은 이 같 은 관례를 따르고 있습니다. 일각에서는 CoC 패러다임을 적용하면 자유도가 떨어진다는 의견도 있지만 팀 단위로 진행되는 소프 트웨어 개발 프로젝트의 특성상 표준화와 규격화가 정해지지 않는다면 공유와 협업이 힘들어지고 잘 못된 설정 등으로 인한 버그 발생 소지가 크며, 유지보수가 어려워지는 문제가 있습니다. 예를 들어, 블로그 서비스를 개발 중인데 게시 글의 카테고리를 저장하는 테이블인 article _

categories를 만들었을 경우 라라벨은 관련 모델 클래스는 ArticleCategory라고 가정하고 동작하므 로 개발자는 모델과 일치하는 테이블 이름이 다른 경우에만 설정하면 됩니다. 또한 로그인을 처리하는 URL이 /auth/login(라라벨 5.1) 또는 /login(라라벨 5.2)이라고 가정하고 있으며, 로그인에 성공할 경우 /home URL로 리다이렉트하도록 관례가 설정돼 있으므로 설정을 생 략하고 별도의 URL을 사용할 경우에만 설정하면 됩니다.

CoC는 이처럼 많은 설정 파일 관리와 설정의 부담에서 벗어나 애플리케이션 개발에 집중할 수 있게 해주는 훌륭한 패러다임이지만 한 가지 문제가 있습니다. 즉, 관례를 모르면 어떻게 동작하는지 이해

31


32

쉽게 배우는 라라벨 5 프로그래밍

할 수가 없으므로 관례를 따르지 않는 경우(레거시 데이터베이스 등)나 커스터마이징 시 어려움을 겪 을 수 있으며 어디서 관례를 찾아야 할지 파악하기 힘들다는 점입니다. 이 책에서는 이런 문제를 해결하기 위해 라라벨의 각 기능을 설명할 때 미리 정해진 관례에 대해서도 설명함으로써 라라벨 프레임워크에 익숙해지도록 도울 것입니다.

1.9 _ 우아한 문법과 코딩 표준 초기 PHP는 사용자의 요구에 맞게 다양한 C 라이브러리를 언어에 포함시켰으며 C 라이브러리 사용 자를 고려해 함수 이름이나 매개변수의 순서 등에서 최대한 C 라이브러리와의 호환성을 확보하기 위 해 노력을 기울였습니다. 그 결과, 기존 C 라이브러리 사용자들은 쉽게 PHP에 적응할 수 있었지만 반대로 일관성이 없다는 단 점이 있었습니다. 실제로 개발자들이 PHP를 싫어하는 주요 이유 중 하나는 일관성 없는 문법과 함수 사용법이기도 합니다. 예를 들어, html_entity_decode 함수와 쌍을 이루는 함수는 htmlentities이고, 문자를 소문자로 바 꾸는 함수는 strtolower( to를 사용)이지만 Hex 문자열을 바이너리로 바꾸는 함수는 hex2bin( to 가 아닌 2를 사용)입니다. 또한 파일이 있는지 확인하는 함수는 file_exist이지만 파일을 여는 함수는

fopen입니다. 이러한 일관성 결여는 PHP를 사용할 때 개발자를 혼란스럽게 하고 생산성이 떨어지며 자주 쓰지 않 는 함수를 사용할 경우 매번 매뉴얼을 찾게 만들고 코딩 실수를 유발하는 원인으로 작용했습니다. 라라벨은 기존 PHP 함수에 대해 일관성 있는 이름의 래퍼를 제공하고 기능을 확장했습니다. 예를 들 어, 파일 시스템을 다루는 함수는 Storage 클래스에 통합하고 이를 통해 파일이 로컬에 있든 아마존 클라우드에 있든 상관없이 일관성 있게 사용할 수 있습니다. [예제 1.6] FileSystem 래퍼를 이용한 파일 처리

<?php // 아마존 S3 클라우드 디스크 객체 반환 $s3disk = Storage::disk('s3'); // 로컬 디스크 객체 반환 $localDisk = Storage::disk('local');


01 _ 라라벨 소개

// 로컬 디스크에서 file.jpg 존재 여부 확인 $exists = $localDisk ->exists('file.jpg'); // 아마존 스토리지 파일의 마지막 변경 일시 확인 $time = $s3disk->lastModified('file1.jpg');

또한 사용할 때마다 혼란스러운 PHP 배열에 대해 도우미 함수를 제공하고 있으므로 편리하게 사용 할 수 있습니다. 기존 PHP에서는 배열에 요소를 추가할 경우 array_push()를 사용하는데, 키/값 구 조를 바로 넣을 수는 없습니다. [예제 1.7] 기존 배열 처리 방식

<?php $array = ['foo' => 'bar']; // 배열에 key => value 형식으로 요소 추가 array_push($array, 'key', 'value'); var_dump($array);

위 코드를 실행하면 의도와는 달리 ‘key’와 ‘value’라는 값이 각각 배열의 요소로 들어간 것을 확인할 수 있습니다. $ php array_add1.php .array(3) { 'foo' => string(3) "bar" [0] => string(3) "key" [1] => string(5) "value" }

이를 의도한 대로 동작하게 하려면 $array[‘key’] = ‘value’; 구문을 사용해야 합니다.

33


34

쉽게 배우는 라라벨 5 프로그래밍

이처럼 배열에 요소를 추가할 경우 array_push()를 사용하지만 배열에 키/값 요소를 추가할 경우 다 른 문법을 사용해야 하는 것은 코딩의 일관성을 떨어뜨리고 코딩 실수를 유발할 수 있다는 문제가 있 습니다. 라라벨은 PHP의 기본 함수 가운데 일관성이 떨어지는 함수에 대해 도우미( helper) 함수를 제공합니 다. 배열 내에 키가 존재하지 않을 경우 요소를 추가하는 array_add() 도우미 함수를 제공하므로 배 열에 요소를 추가할 경우 다음과 같이 일관성 있게 코드를 작성할 수 있습니다. <?php $array = ['foo' => 'bar']; /** array:2 [ "foo" => "bar" "key" => "value" ] */ $array = array_add($array, 'key', 'value');

아울러 클래스와 메서드의 이름을 지을 때는 언더바(_) 사용을 지양하고, 클래스의 경우에는 UrlRou

table처럼 맨 앞글자와 단어의 첫 글자를 대문자로 쓰는 표기법( StudlyCase)을 사용하며, 메서드 의 경우 첫 글자를 소문자로 쓰는 낙타 표기법( camelCase)을 권장합니다(14.9 PHP 표준 권고 중

PSR-2 참고). 이러한 관례에 익숙해지면 다른 개발자와의 협업이 쉬워지고 가독성 있고 간결한 코 드를 작성할 수 있습니다. 그 결과, 생산성이 높아지고 버그 발생 가능성을 줄어듭니다.

1.10 _ 국제화 지원 다양한 언어의 사용자를 대상으로 웹 애플리케이션을 개발할 경우 국제화( Internationalization;

i18n)를 고려한 설계와 개발이 필요합니다. 국제화를 적용할 때 사용하는 언어와 환경에 맞게 다양한 언어로 서비스를 제공하는 것이 중요한데, 이를 위해 라라벨은 locale 환경변수를 설정하고 번역된 메시지 파일을 만들어 주면 설정된 언어에 맞는 메시지 파일을 로딩해 다국어 애플리케이션을 제공할 수 있게 지원합니다.


01 _ 라라벨 소개

다음과 같이 언어별 메시지 파일(기본값: resources/lang/en/)을 언어명(한글의 경우 ko) 폴더에 복사한 후에 해당 파일을 수정하면 됩니다. 각 언어별 메시지 파일은 전 세계의 다양한 공헌자들에 의 해 번역돼 있습니다. /resources/lang/ en messages.php ko messages.php

예를 들어, 프랑스어 서비스를 제공할 경우 검증 실패 시 표시할 메시지 파일을 resources /

lang/fr/messages.php에 만들고 번역한 내용을 키/값 형식의 배열로 기술하면 해당 메시지를 Lang::get($key) 메서드나 이를 간략화한 trans($key) 메서드를 통해 로딩할 수 있습니다. 다음은 특정 값보다 큰 데이터가 입력된 경우 오류 메시지를 로딩하는 예제입니다. public function getMaxFailedMessage() { return Lang::get('messages.max.numeric', ['max'=>50, 'attribute' => 'username']); }

실제 오류 메시지는 resources/lang/fr/messages.php 파일에 다음과 같이 배열로 기술돼 있으므로 언어별로 손쉽게 관리할 수 있으며, 새로운 언어가 필요할 경우 해당 메시지 파일만 번역해서 추가하 면 됩니다. <?php return [ 'max' => [ 'numeric' => 'The :attribute may not be greater than :max.', ], ];

메시지 파일 중 런타임에 변경돼야 부분이 있으면 위치 표시기( placeholder)를 통해 지원할 수 있습 니다. 표시기는 : 뒤에 속성명을 지정하는 형식이며, 앞의 예제에서는 :max와 :attribute가 런타임에 동적으로 변경될 매개변수가 됩니다. 따라서 최종 오류 메시지는 다음과 같이 변환됩니다. The username may not be greater than 50.

35


36

쉽게 배우는 라라벨 5 프로그래밍

1.11 _ 손쉬운 테스트 작성한 소프트웨어를 테스트하는 것은 조기에 문제를 식별하고 최소의 비용으로 해결하기 위한 중 요한 프로세스입니다. 하지만 PHP로 개발할 경우 단위 테스트( unit test)나 기능 테스트( function

test)를 하기가 어려워서 별도로 하지 못했고 웹 브라우저를 통해 웹사이트의 메뉴별 기능을 직접 테 스트하는 경우가 많았습니다. 그런데 기능이 잘 수행되면 상관없지만 오류가 발생하면 어느 단계에서 발생한 문제인지 원인을 찾고 해결하는 데 많은 시간을 쏟아야 했습니다. 예를 들어, 쇼핑몰에서 사용자의 구매 목록을 표시하는 기능을 테스트할 경우 다음과 같은 프로세스 에서 출력된 화면이 이상하다고 가정해 보겠습니다.

[그림 1.10] 업무 흐름의 예

이 경우 화면 출력 기능의 이상일 수도 있지만 그 앞의 프로세스에서 발생한 문제가 화면 출력 단계로 전이됐을 수도 있습니다. 단위 테스트가 작성돼 있지 않다면 매번 브라우저로 연결해서 위 단계를 수 행하면서 테스트를 진행해야 합니다. 각 단계별로 분리해서 단위 테스트를 할 수 있다면 각 프로세스를 분리해서 테스트함으로써 문제 범 위를 좁힐 수 있고 이를 통해 조기에 조치할 수 있을 것입니다.


01 _ 라라벨 소개

PHP 세계에도 PHPUnit이라는 훌륭한 단위 테스트 프레임워크가 있지만 이를 설치하고 테스트 케이 스를 만들어서 테스트하는 것은 단위 테스트에 익숙한 개발자가 아니면 하기 어려웠습니다. 대신 라 라벨은 PHPUnit과 유기적으로 통합돼 있으며, 단위 테스트를 할 수 있도록 편리한 기능과 템플릿을 제공하고 있으므로 손쉽게 단위 테스트를 만들고 실행할 수 있게 도와줍니다. 테스트 프로세스가 잘 정착되면 코드가 변경되어 버전 관리 시스템에 커밋될 때마다 자동으로 단위 테스트를 실행해 테스트에 통과한 경우에만 다른 환경에 배포하는 등 개발과 변경 업무를 자동화할 수 있는 기반이 됩니다.

정리 이번 장에서는 라라벨을 간략하게 소개하고 라라벨의 특징과 장점을 살펴봤습니다. 지금부터 라라벨 프레임워크를 본격적으로 사용하기 위한 개발 환경을 구축하겠습니다.

37


쉽게 배우는 라라벨 5 프로그래밍 : 견고하고 확장성 있는 PHP 웹 애플리케이션 개발  

정광섭 지음 | 오픈소스 & 웹 시리즈_077 | ISBN: 9791158390365 | 28,000원 | 2016년 05월 20일 발행 | 476쪽 | Laravel, PHP, PHP7, 라라벨, 라라벨 5, 웹 개발 프레임워크

Read more
Read more
Similar to
Popular now
Just for you