블로그 이미지
물결(Wave)
하고 싶은 것만 하며 살고 싶다

calendar

        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  

이번 시간에는 주소록의 뼈대를 만들것이다.
간단한 DB 테이블을 하나 만들고, PHP를 이용해서 DB작업을 위한 서버프로그램을 만들것이다.
그리고 다음장에서 주소록의 핵심인 주소록의 데이터를 사용자가 입력/수정/삭제 할 수 있는 HTML페이지를 작성하도록 하겠다.

DB

주소록은 간단하게 만들기로 하였다.
이름,연락처,주소 그리고 인덱스.
총 4개의 필드만 필요하다. 뭐 더 만들고 싶은 필드가 있으면 그건 각자 알아서...

CREATE TABLE addressbook (
  idx INT NOT NULL AUTO_INCREMENT ,
  name VARCHAR( 30 ) NOT NULL ,
  tel VARCHAR( 30 ) NOT NULL ,
  addr VARCHAR( 100 ) ,
  PRIMARY KEY ( idx )
)



서버프로그램(PHP)

서버프로그램은 클래스를 사용하기로 한다.
혹, 클래스가 잘 적응이 안되는 분도 이기회에 클래스를 한번 써보는것도 나쁘지는 않으리라 생각한다.
클래스를 설계할때 고민해야 할 것은 역할의 분리이다. 하나의 메소드에게는 한가지 일만 시키는것이 좋다.

직원 A에게 복사를 하는 일과 서류를 작성하는일, 거래처를 관리하는 일을 모두 맡겨왔는데
갑작스레 A가 사표를 낸다면

  1. A가 해왔던 세 가지 일을 모두 할 줄 아는 직원을 뽑거나
  2. 각각의 일을 맡을 세명의 직원을 뽑아야 한다.

하지만 처음부터 각 업무를 서로 다른 사람이 해왔다면 필요한 일만 할줄 아는 사람을 새로 뽑으면 된다.

우리의 주소록은 비교적 간단하므로 클래스를 구성하는데 별 무리가 없을것이다.
주소록 클래스가 할일을 살펴보면

  1. 주소록에 새로운 데이터 추가
  2. 입력된 데이터의 수정/삭제
  3. 입력된 데이터 추출

이상이다.

그럼 클래스를 만들어보자.

* 주소록 클래스는 PHP4도 호환이 가능하도록 작성할 예정이므로 __constructor__ 같은 PHP5전용 코드는 사용하지 않을것이다.

[class_addressbook.php]

class AddressBook{
   var $conn;

   //생성자
   function AddressBook($conn=Null){
       if($conn == Null){
           return false;
       }

       $this->conn = $conn;
   }

   //데이터 입력
   function addAddress(){}

   //데이터 수정
   function updateAddress(){}

   //데이터 삭제
   function deleteAddress(){}

   //데이터 추출
   function getAddress(){}
}

AddressBook 클래스의 기본 골격은 위와 같다.
DB연동이 주된 업무이니 생성자에서는 DB 커넥터를 기본으로 지정한다.

이제 메소드를 하나하나 구현해보자

1.데이터 입력: addAddress()

입력해야 할 필드는 총 4개인데 그중 idx는 자동으로 생성되니 addAddress 메소드에는 3개의 값만 던져주면 되겠다. 바로 이름,연락처,주소이다. 그중 주소는 NOT NULL 이 아니니 이점에 유의하자

function addAddress($name,$tel,$addr=Null){
   if(empty($name) == true || empty($tel) == true){
       return false;
   }
   //주소값이 주어지지 않으면 db에 null 을 입력한다. 공백을 입력하게 되면 is null 같은 검색이 안된다.
   if($addr == Null){
       $addr = 'null';
   }else{
       $addr = "'".$addr."'";
   }

   $qry = "INSERT INTO addressbook SET\n"
           ."name='".$name."',"
           ."tel='".$tel."',"
           ."addr=".$addr;

   $res = mysql_query($qry,$this->conn);

   //입력이 성공하면 해당 row의 index 번호를 반환한다
   if($res != false){
       return mysql_insert_id();
   }else{
       return false;
   }
}


2.데이터 수정: updateAddress()

데이터의 수정은 데이터의 입력과 비슷하다. 단지 어떤 데이터를 수정하느냐를 결정하는 idx가 주어지는 것만 다를뿐이다.

function updateAddress($idx,$name,$tel,$addr=Null){
   if(empty($idx) == true || empty($name) == true || empty($tel) == true){
       return false;
   }

   if($addr == Null){
       $addr = 'null';
   }else{
       $addr = "'".$addr."'";
   }

   $qry = "UPDATE addressbook SET\n"
           ."name='".$name."',"
           ."tel='".$tel."',"
           ."addr=".$addr."\n"
           ."WHERE idx=".$idx;

   return mysql_query($qry,$this->conn);
}


3.데이터 삭제: deleteAddress()


데이터의 삭제는 더 간단하다. 삭제할 row의 idx값만 주면 된다.

function deleteAddress($idx=Null){
   if($idx == Null){
       return false;
   }

   $qry = "DELETE FROM addressbook WHERE idx=".$idx;

   return mysql_query($qry,$this->conn);
}



4.데이터 추출: getAddress() + getAllAddress()

데이터 추출은 좀 다르게 구현을 해야 한다. 하나의 레코드만 추출 할 경우와 전체 레코드를 추출할 경우를 구분해야 하기 때문이다. 위에서도 하나의 말했듯 메소드에게는 하나의 일만 시키는 것이 좋으므로 데이터 추출은 두개의 메소드로 구현하기로 하자 getAddress()와 getAllAddress() 가 바로 그것이다.

function getAddress($idx=Null){
   if($idx == Null){
       return false;
   }

   $qry = "SELECT * FROM addressbook WHERE idx=".$idx;
   $res = mysql_query($qry,$this->conn);

   if(mysql_num_rows($res) > 0){
       return mysql_result($res,0);
   }else{
       return Null;
   }
}
function getAllAddress(){
   $qry = "SELECT * FROM addressbook";
   $res = mysql_query($qry,$this->conn);

   if(mysql_num_rows($res) > 0){
       $result = array();
       while($row = mysql_fetch_assoc($res)){
           array_push($result,$row);
       }

       return $result;
   }else{
       return Null;
   }
}

이제 필요한 메소드가 다 만들어졌다.
그런데 데이터 입력과 수정작업을 처리하는 메소드에 중복되는 코드가 보인다.
바로 SQL 쿼리문을 작성하는 부분인데 이부분은 따로 쿼리 작성 메소드를 만들어서 빼는게 좋겠다.
이름하여 캡슐화...

function makeQuery($name,$tel,$addr=Null){
   if(empty($addr) == true){
       $addr = 'null';
   }else{
       $addr = "'".$addr."'";
   }

   $str = "name='".$name."',\n"
         ."tel='".$tel."',\n"
         ."addr=".$addr;

   return $str;
}

캡슐화를 했으니 addAddress()와 updateAddress()메소드를 수정해야한다.
전체를 수정하는건 아니고 SQL쿼리 작성 부분만 수정하면 된다.

addAddress()
   $qry = "INSERT INTO addressbook SET\n";
   $qry .= $this->makeQuery($name,$tel,$addr);

updateAddress()
   $qry = "UPDATE addressbook SET\n";
   $qry .= $this->makeQuery($name,$tel,$addr);
   $qry .= " WHERE idx=".$idx;

드디어 AddressBook 클래스가 완성됐다.
사실 제대로된 객체지향 프로그래밍을 하자면 AddressBook 클래스 외에 Address 클래스도 필요하다.
하지만 지금까지의 과정도 쉽고 단순하게 하자는 당초의 계획과는 달리 복잡해진감이 없지않으므로 Address클래스는 일단 생략하고 클라이언트 프로그램 완성 후에 리팩토링을 하겠다.


테스트

DB에 테이블도 만들었고 클래스도 만들었으니 테스트를 해보자.
웹프로그래밍에 TDD(Test Driven Develope)적용이 필요한지에 대해서는 의견이 분분하지만 개념을 알필요는 충분하다고 본다.

에디터에서 다음과 같은 코드를 작성한 후 브라우져로 결과를 확인해보자.
<?php
assert_options(ASSERT_ACTIVE, 1);
assert_options(ASSERT_WARNING, 0);
assert_options(ASSERT_QUIET_EVAL, 1);
assert_options(ASSERT_CALLBACK, 'assert_handler');
assert_options(ASSERT_BAIL,1);

function assert_handler($file,$line,$code){
   echo "Assertion Failed:<br />
       File '$file'<br />
       Line '$line'<br />
       Code '$code'<br />";
}

include_once 'db_conn.php'
include_once 'class_addressbook.php';

echo 'start test<br />';

assert('$BOOK = new AddressBook($conn)');
echo 'class construction test ... [OK]<br />';

assert('$BOOK->addAddress("이효리","011-1111-1111")');
assert('$BOOK->addAddress("강동원","011-2222-2222","우리집")');
assert('$BOOK->addAddress("Jackson","060-3333-3333","America")');
echo 'address data INSERT test ... [OK]<br />';

assert('$BOOK->updateAddress(1,"이효리","016-4444-4444","우리집")');
assert('$BOOK->updateAddress(2,"강동웜","011-2222-2222","북한")');
echo 'address data UPDATE test ... [OK]<br />';

assert('$BOOK->getAddress(3)');
echo 'an address data GET test ... [OK]<br />';

assert('$BOOK->deleteAddress(3)');
echo 'an address data DELETE test ... [OK]<br />';

assert('$BOOK->getAllAddress()');
echo 'all address data GET test ... [OK]<br />';

echo 'All Test Success!!';

$qry = "DELETE FROM addressbook";
mysql_query($qry,$conn);

$qry = "ALTER TABLE addressbook auto_increment=1";
mysql_query($qry,$conn);
?>

브라우져에 All Test Success!! 가 출력됐다면 성공이다.

테스트가 성공했으면 실제 쓸 소스를 작성해야 한다.
이미 테스트 코드에서 다 만들었으니 그냥 가져다 쓰면 된다.

[execute_address.php]

//include =================================================
include_once 'db_conn.php';
include_once 'class_addressbook.php';


//request vars ============================================
$name = isset($_POST['name'])?$_POST['name']:Null;
$tel     = isset($_POST['tel'])?$_POST['tel']:Null;
$addr  = isset($_POST['addr'])?$_POST['addr']:Null;
$idx    = isset($_POST['idx'])?$_POST['idx']:Null;
$job    = isset($_POST['job'])?$_POST['job']:Null;

$result = false;

if($job == Null || false !== $BOOK = new AddressBook($conn)){
   switch($job){
       case('add'):
           $result = $BOOK->addAddress($name,$tel,$addr);
       break;

       case('update'):
           $result = $BOOK->updateAddress($idx,$name,$tel,$addr);
       break;

       case('delete'):
           $result = $BOOK->deleteAddress($idx);
       break;

       case('get'):
           $result = $BOOK->getAddress($idx);
       break;

       case('get_all'):
           $result = $BOOK->getAllAddress();
       break;
   }
}


준비끝

아직 완성은 아니지만 서버쪽 코딩이 끝났다.
완성이 아니라고한 이유는 php 처리 결과를 javascript 로 보내는 코드가 빠졌기 때문이다.
이 부분은 클라이언트 코딩할때 추가하기로 한다. 한글 인코딩 문제도 있고 JSON과 XML등등 데이터 가공과정을 거쳐야 하기때문이다.

여기까지는 그리 힘들지 않을것이라 본다.
어려운 부분은 없었던것 같고, 다만 클래스나 assert() 함수가 낯선 분들이 있을지도 모르겠다.
다음 포스팅에서는 AJAX애플리케이션의 핵심인 클라이언트 코딩을 하겠다.
DOM을 많이 사용해야하니 DOM에 자신 없는 분은 미리 [DOM]에 대해 공부를 하시길...
다음 링크를 따라가면 DOM에 대해 배울수 있다.

DOM3 - http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/Overview.html#contents
DOM3 Event - http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html
HTML DOM - http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-39872903

신고
크리에이티브 커먼즈 라이선스
Creative Commons License
posted by 물결(Wave)

AJAX가 무엇인지는 검색을 통해 쉽게 찾을 수 있으니 생략하기로 한다.
다만 한가지 당부의 말을 하고 싶어 몇자 적는다.

당신이 AJAX에 대하여 무엇을 상상했건 당신이 상상한 그 이상도 그 이하도 아닐것이다.
AJAX는 혜성처럼 등장한 새로운 언어도 아니고 무언가 획기적인 방법으로 화려한 어플리케이션을 개발하게 해주는 기술도 아니다.

꼭 위의 말을 기억하길 바란다.
기대가 크면 실망도 크니까....

내가 이 포스팅을 하게 된 이유는 아직 AJAX를 잘 모르는 친구놈에게 AJAX를 가르치기 위함이다.
때문에 글 내용은 차분하면서도 세세하게 예제를 통해 AJAX에 대해 설명할 것이다.


준비

앞으로 AJAX를 설명하면서 만들 어볼 예제는 주소록이다.

본 내용과는 관련이 없지만 혹시 Ruby on Rails 를 모르지만 해보고 싶은 분은
여기를 클릭해서 주소록 예제를 해보시길 :)

주소록의 구조는 간단하다.
빈 주소록에 새 레코드를 작성하고 작성된 레코드를 수정하거나 삭제하는 기능이 전부다.
물론 이 모든 작업은 AJAX를 사용하여 페이지 이동 없이 하나의 열려진 페이지 내에서 이루어질것이다.

그럼 본격적으로 시작....



시작

우선 AJAX의 핵심(나는 이것이 핵심이라고 생각한다.)인 XMLHttpRequest 객체에 대해 알아보자.


XMLHttpRequest

property:

onreadystatechange Sets or retrieves the event handler for asynchronous requests.
readyState Retrieves the current state of the request operation.
responseBody Retrieves the response body as an array of unsigned bytes.
responseText Retrieves the response body as a string.
responseXML Retrieves the response body as an XML Document Object Model (DOM) object.
status Retrieves the HTTP status code of the request.
statusText Retrieves the friendly HTTP status of the request.

method:
abort Cancels the current HTTP request.
getAllResponseHeaders Returns the complete list of response headers.
getResponseHeader Returns the specified response header.
open Assigns method, destination URL, and other optional attributes of a pending request.
send Sends an HTTP request to the server and receives a response.
setRequestHeader Adds custom HTTP headers to the request.


각각의 속성과 메서드들은 MSDN에서 자세하게 설명하고 있다.

XMLHttpRequest 객체는 브라우져마다 생성방법이 조금씩 다르다.

IE 6이하의 버전에서는 다음과 같다.

new ActiveXObject('Msxml2.XMLHTTP')
new ActiveXObject('Microsoft.XMLHTTP')


IE 7부터 XMLHttpRequest을 지원하며 파이어폭스,사파리등에서는 이미 지원하고 있다.
따라서 이들의 브라우져에서의 생성 방법은 다음과 같다.

  new XMLHttpRequest();


이걸 한데 묶어보면 다음과 같다.
var request = false;

try {
request = new XMLHttpRequest();
} catch (trymicrosoft) {
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (othermicrosoft) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (failed) {
request = false;
}
}
}
XMLHttpRequst 객체가 만들어졌다.
서버와 클라이언트가 데이터를 주고 받을 수 있는 길이 열린것이다.
앞으로 저 길 위에서 주소록에 사용될 데이터들이 왔다리 갔다리 할 것이다.
이번 순서는 길을 연것으로 만족하자.
그리고 XMLHttpRequest 객체의 속성과 메서드들을 꼼꼼히 살펴보기 바란다.
인터넷에서 흔하게 찾을 수 있는 누군가에의해 만들어진 함수를 쓰는 것도 나쁘지는 않으나 적어도 XMLHttpRequest 객체의 각 속성과 메서드의 역할은 제대로 알고 있어야 할 것이다.

다음 순서에서는 주소록을 위한 서버 프로그램(PHP)과 클라이언트 프로그램(HTML)을 만들어 볼 것이다.
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
posted by 물결(Wave)

xmlhttprequest 객체를 사용하면 참 편리하다.
이른바 AJAX의 핵심이 바로 이 객체가 아닌가 한다.

xmlhttprequest 객체를 사용하여 데이터를 PHP파일로 송신하면
데이터는 utf-8로 인코딩되어 전송된다.

var url = some url;
var param = 'id=myid&password=mypass&name=유시형';


xmlHttpPost(url,param,result function);

위 처럼 인자값에 한글이 들어갈 경우에는
제대로 전송이 되지 않는다.

var param = 'id=myid&password=mypass&name=' + escape(encodeURIComponent('유시형'));

encodeURIComponent,escape 두 함수를 이용해서 가공을 한번 해줘야 제대로 전달이 된다.


다음으로 PHP에서 위 인자값을 받을때는

$id = $_POST['myid'];
$pass = $_POST['password'];
$name = iconv('UTF-8','EUC-KR',urldecode($_POST['name']));

자바스크립트에서 함수를 적용한 역순으로 decoding을 먼저 해주고
문자셋을 euc-kr로 변경해주면 된다.

물론,
서버셋팅이 UTF-8로 되어 있다면 위처럼 귀찮은 짓은 하지 않아도 된다.
역시 대세는 UTF-8이다....
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
posted by 물결(Wave)
prev 1 next

티스토리 툴바