게시판 DB 구조 - gesipan DB gujo

지금까지 CodeIgniter 개발 환경을 구성하고 기본 구조에 대해 알아봤습니다. 

4장은 MySQL 테이블을 구성하고 게시판을 실제로 만들어 보면서  CodeIgniterd의 MVC 패턴 사용방법과 컨트롤러의 몇 가지 유형을 알아봅니다.

게시판은 하나의 테이블로 원 글과 댓글을 표현하는 구조이며 리스트, 검색, 페이징, 상세보기, 쓰기, 수정, 삭제로 이루어져 있습니다.

개발을 할 때 제일 먼저 시작하는 작업인 테이블 만들기부터 시작합시다.

4.1 게시판 테이블 만들기

 ci_book 데이터베이스를 생성하고 MySQL 콘솔에 접속합니다.


 mysqladmin -uroot -p create ci_book

 mysql -uroot -p ci_book

 grant select, insert, update, delete, create, alter, drop on ci_book .* to 'book_user'@'localhost' identified by 'book_password';


 데이터베이스를 생성하고 사용자를 생성했습니다. 이제 테이블을 만들어보겠습니다.


 ci_board 테이블

 int            board_id

 int            board_pid

 varchar       user_id

 varchar        user_name

 varchar        subject

 text            contents

 int             hits

 date           reg_date

 MySQL 콘솔 명령어

  use ci_book

  CREATE TABLE ci_board (

  board_id int(10) NULL AUTO_INCREMENT PRIMARY KEY,

  board_pid int(10) NULL DEFAULT 0 COMMENT '원글 번호',

  user_id varchar(20) COMMENT '작성자ID',

  user_name varchar(20) NOT NULL COMMENT '작성자 이름',

  subject varchar(50) NOT NULL COMMENT '게시글 제목',

  contents text NOT NULL COMMENT '게시글 내용',

  hits int(10) NOT NULL DEFAULT 0 COMMENT '조회수',

  reg_date datetime NOT NULL COMMENT '등록일',

  INDEX board_pid (board_pid)

 )

 COMMENT='CodeIgniter 게시판'

 COLLATE='utf8_general_ci'

 ENGINE=MyISAM;

 show tables;

 desc ci_board;


 

 마지막 명령어를 통해 ci_board의 구조를 확인함으로써, 데이터베이스 생성, 사용자 생성 및 권한주기, 테이블 생성이 끝났습니다. 

4.2 목록 보기 기능 만들기

 이번 절에서는 4.1절에서 생성한 테이블에 가상 데이터를 넣고 그 내용을 불러오는 프로그램을 만들어 보겠습니다.

 먼저 화면에 리스트만 뿌리고 그 다음에 페이징을 붙이고 검색기능을 추가하겠습니다.

 4.2.1 리스트 불러오기

    먼저 MySQL에 가상 데이터를 입력하도록 하겠습니다.


  INSERT INTO ci_board(user_id, user_name, subject, contents, hits, reg_date) VALUES ('advisor', 'Palpit', 'First Note', 'Test', 0, '2015-08-11 11:11:21');

  INSERT INTO ci_board(user_id, user_name, subject, contents, hits, reg_date) VALUES ('advisor', 'Palpit', 'Second Note', 'Test', 0, '2015-08-11 11:11:21');

  INSERT INTO ci_board(user_id, user_name, subject, contents, hits, reg_date) VALUES ('advisor', 'Palpit', 'Third Note', 'Test', 0, '2015-08-11 11:11:21');

  INSERT INTO ci_board(user_id, user_name, subject, contents, hits, reg_date) VALUES ('advisor', 'Palpit', 'Fourth Note', 'Test', 0, '2015-08-11 11:11:21');

  INSERT INTO ci_board(user_id, user_name, subject, contents, hits, reg_date) VALUES ('advisor', 'Palpit', 'Fifth Note', 'Test', 0, '2015-08-11 11:11:21');

  INSERT INTO ci_board(user_id, user_name, subject, contents, hits, reg_date) VALUES ('advisor', 'Palpit', 'Sixth Note', 'Test', 0, '2015-08-11 11:11:21');

  INSERT INTO ci_board(user_id, user_name, subject, contents, hits, reg_date) VALUES ('advisor', 'Palpit', 'Seventh Note', 'Test', 0, '2015-08-11 11:11:21');

  INSERT INTO ci_board(board_pid, user_id, user_name, subject, contents, hits, reg_date) VALUES (1, 'zhfldi4', 'Cyzone', 'Comment Test', 'Comment', 0, '2015-08-12 23:11:11');

  INSERT INTO ci_board(board_pid, user_id, user_name, subject, contents, hits, reg_date) VALUES (1, 'zhfldi4', 'Cyzone', 'Comment Test2', 'Comment', 0, '2015-08-12 23:11:11');


 입력된 데이터를 확인하기 위해 아래 명령어를 입력합니다.

 SELECT * FROM ci_board;

게시판 DB 구조 - gesipan DB gujo

  목록에서 불러올 가상 데이터가 준비되었으니 소스 코딩을 해보겠습니다. 먼저 컨트롤러를 작성합니다.

  (todo 프로젝트와 마찬가지로 bbs 폴더를 생성하여 CodeIgniter를 복사해서 환경을 구성해주세요)

 * board.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

<?php

if (!defined('BASEPATH'))

exit('No direct script access allowed');

/**

 *  게시판 메인 컨트롤러

 */

class Board extends CI_Controller {

function __construct() {

parent::__construct();

$this -> load -> database();

$this -> load -> model('board_m');

$this -> load -> helper(array('url''date'));

}

/**

     * 주소에서 메서드가 생략되었을 때 실행되는 기본 메서드

     */

public function index() {

$this -> lists();

}

/**

     * 사이트 헤더, 푸터가 자동으로 추가된다.

     */

public function _remap($method) {

// 헤더 include

$this -> load -> view('header_v');

if (method_exists($this$method)) {

$this -> {"{$method}"}();

}

// 푸터 include

$this -> load -> view('footer_v');

}

/**

     * 목록 불러오기

     */

public function lists() {

$data['list'= $this -> board_m -> get_list();

$this -> load -> view('board/list_v'$data);

}

}

cs

  모델을 이용하려면 데이터베이스에 연결해야 하는데 그 부분은 application/config/database.php 에 4.1절에서 만든 사용자, 비밀번호, HOST, 데이터베이스 명을 입력하고 자동로딩 라이브러리 부분에 데이터베이스를 선언하여 사용합니다.

* bbs/application/config/database.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

/*

| -------------------------------------------------------------------

| DATABASE CONNECTIVITY SETTINGS

| -------------------------------------------------------------------

| This file will contain the settings needed to access your database.

|

| For complete instructions please consult the 'Database Connection'

| page of the User Guide.

|

| -------------------------------------------------------------------

| EXPLANATION OF VARIABLES

| -------------------------------------------------------------------

|

|    ['hostname'] The hostname of your database server.

|    ['username'] The username used to connect to the database

|    ['password'] The password used to connect to the database

|    ['database'] The name of the database you want to connect to

|    ['dbdriver'] The database type. ie: mysql.  Currently supported:

                 mysql, mysqli, postgre, odbc, mssql, sqlite, oci8

|    ['dbprefix'] You can add an optional prefix, which will be added

|                 to the table name when using the  Active Record class

|    ['pconnect'] TRUE/FALSE - Whether to use a persistent connection

|    ['db_debug'] TRUE/FALSE - Whether database errors should be displayed.

|    ['cache_on'] TRUE/FALSE - Enables/disables query caching

|    ['cachedir'] The path to the folder where cache files should be stored

|    ['char_set'] The character set used in communicating with the database

|    ['dbcollat'] The character collation used in communicating with the database

|                 NOTE: For MySQL and MySQLi databases, this setting is only used

|                  as a backup if your server is running PHP < 5.2.3 or MySQL < 5.0.7

|                 (and in table creation queries made with DB Forge).

|                  There is an incompatibility in PHP with mysql_real_escape_string() which

|                  can make your site vulnerable to SQL injection if you are using a

|                  multi-byte character set and are running versions lower than these.

|                  Sites using Latin-1 or UTF-8 database character set and collation are unaffected.

|    ['swap_pre'] A default table prefix that should be swapped with the dbprefix

|    ['autoinit'] Whether or not to automatically initialize the database.

|    ['stricton'] TRUE/FALSE - forces 'Strict Mode' connections

|                            - good for ensuring strict SQL while developing

|

| The $active_group variable lets you choose which connection group to

| make active.  By default there is only one group (the 'default' group).

|

| The $active_record variables lets you determine whether or not to load

| the active record class

*/

$active_group = 'default';

$active_record = TRUE;

$db['default']['hostname'= 'localhost';

$db['default']['username'= 'book_user';

$db['default']['password'= 'book_password';

$db['default']['database'= 'ci_book';

$db['default']['dbdriver'= 'mysql';

$db['default']['dbprefix'= '';

$db['default']['pconnect'= FALSE;

$db['default']['db_debug'= TRUE;

$db['default']['cache_on'= FALSE;

$db['default']['cachedir'= '';

$db['default']['char_set'= 'utf8';

$db['default']['dbcollat'= 'utf8_general_ci';

$db['default']['swap_pre'= '';

$db['default']['autoinit'= TRUE;

$db['default']['stricton'= FALSE;

/* End of file database.php */

/* Location: ./application/config/database.php */

cs

  이제 컨트롤러에서 로딩한 모델과 뷰에 대해 알아보도록 하겠습니다.

* bbs/application/models/board_m.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<?php

if (!defined('BASEPATH'))

exit('No direct script access allowed');

/**

 * 공통 게시판 모델

 */

class Board_m extends CI_Model {

function __construct() {

parent::__construct();

}

function get_list($table = 'ci_board') {

$sql = "SELECT * FROM ".$table." ORDER BY board_id DESC";

$query = $this -> db -> query($sql);

$result = $query -> result();

// $result = $query->result_array();

return $result;

}

}

cs

  Line 18: 위 라인처럼 결과를 리턴하면 $result->board_id 형태로 값을 사용할 수 있고, Line 19처럼 결과를 리턴하면 $result['board_id'] 형태로 사용할 수 있습니다.

  이제 뷰 파일의 내용을 살펴보도록 하겠습니다. 컨트롤러에서 선언한 내용은 'board/list_v' 입니다. .php 확장자는 생략합니다. 

  CodeIgniter에서 확장자를 자동으로 붙여서 찾아줍니다. 

  게시판 프로젝트에서는 헤더와 푸터를 나눠서 사용합니다.

 * bbs/application/views/header_v.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8"/>

<meta name="apple-mobile-web-app-capable" content="yes" />

<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />

<title>CodeIgniter</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

<link type="text/css" rel='stylesheet' href="/todo/include/css/bootstrap.css" />

</head>

<body>

<div id="main">

<header id="header" data-role="header" data-position="fixed">

<blockquote>

<p>

만들면서 배우는 CodeIgniter

</p>

<small>실행 예제</small>

</blockquote>

</header>

<nav id="gnb">

<ul>

<li>

<a rel="external" href="/bbs/<?php echo $this -> uri -> segment(1); ?>/lists/<?php echo $this -> uri -> segment(3); ?>"> 게시판 프로젝트 </a>

</li>

</ul>

</nav>

cs

 * bbs/application/views/board/list_v.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

<article id="board_area">

<header>

<h2></h2>

</header>

<h2></h2>

<table cellpadding="0" cellspacing="0">

<thead>

<tr>

<th scope="col">번호</th>

<th scope="col">제목</th>

<th scope="col">작성자</th>

<th scope="col">조회수</th>

<th scope="col">작성일</th>

</tr>

</thead>

<tbody>

<?php

foreach($list as $lt)

{

?>

<tr>

<th scope="row"><?php echo $lt -> board_id;?></th>

<td><a rel="external" href="/bbs/<?php echo $this -> uri -> segment(1); ?>/view/<?php echo $this -> uri -> segment(3); ?>/<?php echo $lt -> board_id; ?>"<?php echo $lt -> subject;?></a></td>

<td><?php echo $lt -> user_name;?></td>

<td><?php echo $lt -> hits;?></td>

<td>

<time datetime="<?php echo mdate("%Y-%M-%j", human_to_unix($lt -> reg_date)); ?>">

<?php echo mdate("%Y-%M-%j", human_to_unix($lt -> reg_date));?>

</time></td>

</tr>

<?php

}

?>

</tbody>

</table>

</article>

cs

 * bbs/application/views/footer_v.php

<footer id="footer">

<dl>

<dt>

<a class="azubu" href="http://www.cikorea.net/" target="blank"> CodeIgniter 한국 사용자포럼 </a>

</dt>

<dd>

Copyright by <em class="black">Palpit</em>.

</dd>

</dl>

</footer>

</div>

</body>

</html>

cs

  코딩은 HTML5 이며 헤더, 콘텐츠, 푸터 세 부분으로 나뉘어 있습니다.

  헤더, 푸터를 모든 페이지에 넣으면 수정사항이 생겼을 시에 일일이 모든 페이지를 수정해야 합니다. 그래서 CodeIgniter의 _remap() 메서드를 이용해 자동으로 헤더와 푸터를 선언합니다. 그래서 뷰에는 헤더, 푸터를 제외한 나머지 콘텐츠 부분만 들어갑니다.

 4.2.2 페이징 만들기

  이번 절에서는 게시판의 중요한 기능 중 하나인 페이징을 구현하도록 하겠습니다. 

  pagination 라이브러리는 주소의 page 변수와 연계해 이동 가능한 링크를 만듭니다. 이동 가능한 링크와 연계되게 모델에서 데이터를 가져오는 부분이 변경되며, 전체 게시물 수를 체크하는 등 추가해야 할 작업이 많습니다.

  처음에는 이해하기 힘들 수 있는데 페이징은 정형화된 형태라서 두고두고 그대로 사용할 수 있습니다.

  페이징을 구현하는 컨트롤러 소스를 살펴보도록 하겠습니다.

 * bbs/application/controllers/board.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

<?php

if (!defined('BASEPATH'))

exit('No direct script access allowed');

/**

 *  게시판 메인 컨트롤러

 */

class Board extends CI_Controller {

function __construct() {

parent::__construct();

$this -> load -> database();

$this -> load -> model('board_m');

$this -> load -> helper(array('url''date'));

}

/**

     * 주소에서 메서드가 생략되었을 때 실행되는 기본 메서드

     */

public function index() {

$this -> lists();

}

/**

     * 사이트 헤더, 푸터가 자동으로 추가된다.

     */

public function _remap($method) {

// 헤더 include

$this -> load -> view('header_v');

if (method_exists($this$method)) {

$this -> {"{$method}"}();

}

// 푸터 include

$this -> load -> view('footer_v');

}

/**

     * 목록 불러오기

     */

public function lists() {

$this -> load -> library('pagination');

// 페이지 네이션 설정

$config['base_url'= '/bbs/board/lists/ci_board/page';

// 페이징 주소

$config['total_rows'= $this -> board_m -> get_list($this -> uri -> segment(3), 'count');

// 게시물 전체 개수

$config['per_page'= 5;

// 한 페이지에 표시할 게시물 수

$config['uri_segment'= 5;

// 페이지 번호가 위치한 세그먼트

// 페이지네이션 초기화

$this -> pagination -> initialize($config);

// 페이지 링크를 생성하여 view에서 사용하 변수에 할당

$data['pagination'= $this -> pagination -> create_links();

// 게시물 목록을 불러오기 위한 offset, limit 값 가져오기

$page = $this -> uri -> segment(51);

if ($page > 1) {

$start = (($page / $config['per_page'])) * $config['per_page'];

else {

$start = ($page - 1* $config['per_page'];

}

$limit = $config['per_page'];

$data['list'= $this -> board_m -> get_list($this -> uri -> segment(3), ''$start$limit);

$this -> load -> view('board/list_v'$data);

}

}

cs

  Line 44: pagiation을 이용하기 위해 라이브러리를 로딩합니다.

  Line 47: pagination 라이브러리 설정 중에서 선언하지 않으면 에러가 날 수 있는 설정입니다.

  다음으로 바뀐 모델의 소스는 아래와 같습니다.

 * bbs/application/models/board_m.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

<?php

if (!defined('BASEPATH'))

exit('No direct script access allowed');

/**

 * 공통 게시판 모델

 */

class Board_m extends CI_Model {

function __construct() {

parent::__construct();

}

function get_list($table = 'ci_board'$type = ''$offset = ''$limit = '') {

$limit_query = '';

if ($limit != '' OR $offset != '') {

// 페이징이 있을 경우 처리

$limit_query = ' LIMIT ' . $offset . ', ' . $limit;

}

$sql = "SELECT * FROM " . $table . " ORDER BY board_id DESC " . $limit_query;

$query = $this -> db -> query($sql);

if ($type == 'count') {

$result = $query -> num_rows();

else {

$result = $query -> result();

}

return $result;

}

}

cs

  모델 부분에서는 페이징 관련 파라미터가 있을 때의 처리와 두 번째 파라미터가 'count' 일때의 처리가 추가되었습니다.

  페이징 연동 링크를 만들고 페이지와 연결된 데이터를 가져와서 뷰에 전달했습니다. 뷰에서는 페이징 링크를 담고 있는 변수 $data['pagination']을 추가해 보도록 하겠습니다.

 * bbs/application/views/board/list_v.php

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

<article id="board_area">

<header>

<h2></h2>

</header>

<h2></h2>

<table cellpadding="0" cellspacing="0">

<thead>

<tr>

<th scope="col">번호</th>

<th scope="col">제목</th>

<th scope="col">작성자</th>

<th scope="col">조회수</th>

<th scope="col">작성일</th>

</tr>

</thead>

<tbody>

<?php

foreach($list as $lt)

{

?>

<tr>

<th scope="row"><?php echo $lt -> board_id;?></th>

<td><a rel="external" href="/bbs/<?php echo $this -> uri -> segment(1); ?>/view/<?php echo $this -> uri -> segment(3); ?>/<?php echo $lt -> board_id; ?>"<?php echo $lt -> subject;?></a></td>

<td><?php echo $lt -> user_name;?></td>

<td><?php echo $lt -> hits;?></td>

<td>

<time datetime="<?php echo mdate("%Y-%M-%j", human_to_unix($lt -> reg_date)); ?>">

<?php echo mdate("%Y-%M-%j", human_to_unix($lt -> reg_date));?>

</time></td>

</tr>

<?php

}

?>

</tbody>

<tfoot>

<tr>

<th colspan="5"><?php echo $pagination;?></th>

</tr>

</tfoot>

</table>

</article>

cs

  Line 39: 뷰 소스에서 <tfoot> 태그를 이용하여 페이징 링크의 HTML 소스를 담고 있는 $pagination 을 화면에 출력하는 것으로 뷰의 작업은 끝입니다.

  이번 포스트에서는 페이징 처리까지 진행하고, 다음 포스트에서 검색 만들기 부터 진행하도록 하겠습니다.

* 이 포스트는 서적 '만들면서 배우는 CodeIgniter 프레임워크'를 참고하여 작성하였습니다