본문 바로가기
개발/PHP

PHP로 MVC구현_제2회

by GetLight 2010. 6. 1.
http://blog.daum.net/bluelinu/8511634?srchid=BR1http%3A%2F%2Fblog.daum.net%2Fbluelinu%2F8511634
===========================================

목차
1. Model 작성


2. View 작성


3. 클래스도면


4. 정리


 


1.Model 작성


 


Model의 작성은 다양해질 수 있지만 여기에서는 몇 가지의 클래스를 조합해 구현해 보고자 한다. 물론 처리하고자 하는 내용에 따라 다르겠지만 대체적으로 다음과 같은 역할을 수행하는 클래스를 정의해 나가게 된다. 



- VO
- DAO
- VO 집합 클래스
- 비즈니스 로직 클래스(Controller로부터 직접 호출되어지는 메서드를 포함)
- 기타 유틸리티 성격의 클래스들
 
각각의 역할을 넘지않는 범위내에서 각 클래스를 구현한다.



이러한 역할 분담에 있어서 검토가 필요한 사항이 request parameter의 처리이다. request parameter는 Web 액세스에 의존적인 정보이다. 따라서 이것을 그대로 비즈니스로직 클래스나 DAO에서 사용해버리면 해당 클래스를 Web이외(배치처리 등)에서는 사용할 수 없게 된다.



하지만 여기서는 request객체(클래스)를 사용해 request parameter를 추상화하려고 한다. 따라서 request parameter를 직접 비즈니스로직 클래스에서 사용한다고 하더라도 해당 호출 전에 값(value)을 세팅해 주면 입력이 가능해져 신경쓰지 않고 request객체를 사용해도 되게 된다.



하지만 session객체(클래스)에 있어서는 주의가 필요하다. 세션도 Web액세스에 의존적이며  실제로 session객체가 소유한 데이터를 비즈니스로직 클래스에서 필요로 하는 경우가 있을 수 있다. 하지만 session은 request parameter와는 달리 일련의 조작을 통해 객체가 가지고 있던 데이터가 변해버릴 우려가 있다. 또한 제1회에서 작성했던 Session클래스의 경우 세션관리 측면에서의 데이터 유지처리까지도 수행되어 버리게 된다.



이러한 경우도 고려하여 좀 귀찮지만 여기서는 「비즈니스로직에서 필요로 하는 session객체의 데이터는 request객체로 copy한 후 사용한다.」 즉 Controller내에서 이 copy처리를 수행하며 비즈니스로직 클래스의 메서드는 request객체만을 전달하는 형태를 취하도록 한다.
그러면 각 클래스에 대해 순서대로 살펴보기로 하자.


 


VO 

VO는 데이터 그 자체를 표현하기 위한 객체이다. 예를 들어 회원정보를 저장하기 위한 클래스의 정의는 다음과 같다.


----------------------------------------------------------------------------------------


 


<?php
class User {
  var $id;
  var $name;
  var $mail;
  var $password;
  var $birthday;


  // 각 속성의 set/get메서드. 생략
}
?>


----------------------------------------------------------------------------------------


 


DAO


제1회에서 Model은 DAO패턴을 적용한다고 했었다. DAO에서는 데이터베이스로의 액세스 과정이 발생한다. 따라서 PHP함수를 직접 호출해도 되지만 여기서는 몇 가지의 DAO에서 공통으로 사용되는 부분을 클래스로 작성해 두기로 한다. 실제로 각 DAO객체는 이 클래스를 상속받아 사용하게 된다.
DAO.php


----------------------------------------------------------------------------------------



<?php


class DAO {


  var $host = "";


  var $dbname = "";


  var $user = "";


  var $password = "";;




  var $con = null;




  function getConnection() {


    if( $this->con == null ) {


      // PostgreSQL로 접속


      $this->con = pg_connect("host=$this->host dbname=$this->dbname" . 


                              "user=$this->user password=$this->password);


    }


    return $con;


  }




  // 이하, SQL 실행용 메서드 등. 생략


}


?>


---------------------------------------------------------------------------


예를 들면 회원정보에 대해 일련의 처리를 하기 위한 DAO 클래스의 정의는 다음과 같다.


UserDAO.php
---------------------------------------------------------------------------


require_once 'DAO.php';


<?php
class UserDAO extends DAO {
  function getConnection() {
    return parent::getConnection();
  }
// 1건 검색
  function findById($id) {
    $sql = "select * from user_table where uid=$id";
    // 중략
    // User객체를 반환
    return new User($id, $name, $mail, $password, $birthday);
  }


  // 전체검색
  function findAll($id) {
    $sql = "select * from user_table order by id";
    $userList = new UserList();
    // 중략
    // 검색된 User정보들에 대한 집합클래스의 객체를 반환
    return $userList;
  }


  // 회원정보를 갱신하는 메서드
  function store($user) {
    $userInfo = Array( "id" => $user->getId(), "name" => $user->getName(),
                 "mail" => $user->getMail(), "password" => $user->getPassword(),
                 "birthday" => $user->getBirthday() );
    // 부모 클래스의 메서드를 호출
    $this->update("user_table", $userInfo, "id=" . $user->getId() );
  }


  // 회원정보를 등록하는 메서드
  function create($user) {
    $id = ... ; // 데이터베이스로 ID를 등록하는 처리
    $userInfo = Array( "id" => $id, "name" => $user->getName(),
                 "mail" => $user->getMail(), "password" => $user->getPassword(),
                 "birthday" => $user->getBirthday() );
    $this->insert("user_table", $userInfo); // 부모클래스의 메서드 호출
  }


}
?>


---------------------------------------------------------------------------


VO 집합 클래스

UserDAO클래스의 findAll()메서드에서 사용할 검색된 모든 VO에 대한 VO집합클래스를 작성한다.여러 가지의 집합클래스가 필요할 경우 상속받아 사용한다.

UserList.php
---------------------------------------------------------------------------


<?php
class UserList {
  var $list = Array();
  function add($element) { $this->list[] = $element; }
  function get($index)   { return $this->list[$index]; }
}
?>


---------------------------------------------------------------------------


하 지만 이 객체를 사용할 때에는 필요한 요소만큼의 VO 인스턴스가 생성되게 된다. 즉 대량의 데이터를 다룰 경우 많은 메모리를 소비하게 된다. 따라서 주의가 필요하다. 대량의 데이터를 다루어야 할 경우에는 PHP가 제공하는 데이터베이스 관련 함수가 반환하는 SQL의 실행결과 객체를 직접 다루기 위한 클래스 등을 작성하는 것도 좋은 방법이 될 것이다.
비즈니스로직 실행 클래스


비 즈니스로직을 실행하는 클래스는 필요에 따라 DAO의 메서드를 호출하면서 수행하고자 하는 처리를 기술하게 된다. 기능, 처리대상별로 클래스를 작성하는 것이 좋다. 예를 들어 회원정보를 취급하는 회원등록을 처리하는 비즈니스로직 클래스는 다음과 같다.

UserLogic.php
---------------------------------------------------------------------------


<?php
require_once 'User.php';
require_once 'UserDAO.php';
require_once 'UserList.php';


class UserLogic {
  var $request;    // 입력
  var $result;     // 결과 저장용 객체


  function UserLogic($request, $result) {
    $this->request =& $request;
    $this->result  =& $result;
  }


  // 회원등록 처리
  function regist() {
    $user =& new User( null, $this->request->get("name"), ... );
    $ud =& new UserDAO();
    // 중략
    if( $ud->create($user) ) {
      $this->result->add("result", true);
    } else {
      $this->result->add("result", false);
    }
  }


  // 로그인 처리
  function login() {
    // 생략
  }


  // 회원정보 갱신처리
  function update() {
    // 생략
  }


  // 회원정보 삭제 처리
  function delete() {
    // 생략
  }
}


?>


---------------------------------------------------------------------------


생성자에는 session 객체는 전달되지 않도록 하고 있지만 앞에서도 얘기했듯이 이 클래스의 재사용성을 고려해 사전에 request객체로 값을 copy해 두기로 한다. 다른 비즈니스로직 클래스도 마찬가지 방법으로 작성하면 된다.



2.View 작성


각 출력 페이지에 해당하는 View의 작성 예제이다. 일반 HTML페이지 내에 result객체로부터 데이터를 추출해(+어느 정도의 비즈니스로직) 포함시키는 정도로 구현된다.
예를 들어 회원등록 확인 페이지는 다음과 같다.

userRegistConfirm!.php
---------------------------------------------------------------------------


<?php
  $u = $result->get("user"); // User객체를 호출
?>
아래의 내용에서 회원등록이 수행된다.


<table>
 <tr>
   <td>이름</td>
   <td><?= htmlspecialchars($u->getName()) ?></td>
 </tr>
 <tr>
   <td>메일주소</td>
   <td><?= htmlspecialchars($u->getMail()) ?></td>
 </tr>
 <tr>
   <td>패스워드</td>
   <td><?= htmlspecialchars($u->getPassword()) ?></td>
 </tr>
 <tr>
   <td>생년월일</td>
   <td><?= htmlspecialchars($u->getBirthday()) ?></td>
 </tr>
</table>


<form action="main.php">
  <input type="hidden" name="action" value="userRegist">
  <input type="hidden" name="type" value="exec">
  <input type="hidden" name="name" value="<?= htmlspecialchars($u->getName()) ?>">
  <input type="hidden" name="mail" value="<?= htmlspecialchars($u->getMail()) ?>">
  <input type="hidden" name="password" value="<?= htmlspecialchars($u->getPassword()) ?>">
  <input type="hidden" name="birthday" value="<?= htmlspecialchars($u->getBirthday()) ?>">
  <input type="submit" value="O K">
 </form>
---------------------------------------------------------------------------


3.클래스 흐름도



 

 




4. 정리


PHP 로 MVC모델(+DAO패턴)에 기초한 설계에 대해 살펴보았다. 재사용성이 일반적인 PHP프로그래밍에 비해 훨씬 높아진다는 것을 알 수 있다. 즉 전체의 흐름을 파악하기 용이하며 객체지향적 설계로 글로벌한 변수가 상당히 줄어 들었다. 또한 유지/보수가 쉬워지는 장점등을 알 수가 있었다.
하지만 여기서 다룬 객체의 생존기간은 단일 request를 처리하는 동안만을 가정하고 진행되었다. sessio에 저장할 수도 있지만 PHP의 경우 session에 저장/호출을 위한 처리비용이 부담이 될 수도 있다.
접속자 수가 많은 사이트에서는 이 방식을 도입하기 앞서 퍼포먼스 측면에서 신중한 테스트가 필요할 것이다.


태그

,