PHP(3) | 목록열기
  • PHP에서 XML을 이용한 SQL문 관리
  • 카테고리 : PHP    2007/04/26 15:30
  • PHP에서 XML을 이용한 SQL문 관리

    개발환경
    PHP5
    Mysql5
    UDF-8

    상황 : DBA에 Programer사이의 원활한 업무효율을 위해서 작성되었습니다.
    물론 상황에 따라서 이 로직은 불편할 수도 있슴.

     

    기본 XML 구문

    <sqls>
     <body>
      <title>자유게시판(게임별)관련 query</title>
      <description>자유게시판 쓰기, 수정, 삭제 외</description>

      <query id="fboardListByPage" type="d">
       <sql>
        SELECT * FROM board
       </sql>
       <db>g_bbs</db>
       <desc>자유게시판 리스트</desc>

       <opt id="mem_id">mem_id like ?</opt>
       <opt id="mem_nick">mem_nick like ?</opt>
       <opt id="bbs_subject">bbs_subject like ?</opt>
       <etc>ORDER BY ori_no ASC, idx ASC LIMIT ?, ?</etc>

       <author>작성자</author>
       <pubdate>작성일</pubdate>
      </query>
     </body>
    </sqls>

     

    PHP XML Parser Class
    /*
     * 작성일 : 2007. 04. 05   작성자 : 정상두
     */

    class commonSqlxml
    {
     private $arQuery = array();
     private $xmlData = array();
     private $arFile = array();  /*XML sql의 파일 위치 정보 */
     private $strId;      /*쿼리의 Unique ID */
     private $parser;

     public function __construct()
     {

     }


     /*
      * 정해진 XML에서 해당 SQL을 가져옴니다.

      arReq :
       - id :   아이디는 파일명과 아이디값을 한개로 포함합니다.

          id 파라메터 예제
          cont.sample.{Unique ID}
          cont.sample.base.{Unique ID}

          cont.sample 는 XML 파일에 대한 규칙입니다.
          파일은 해당 SQL아이디값입니다.   

       - opt: Todo 확장해서 where절등의 조건등에 사용될 파라메터
      */
     public function getSql($arReq)
     {
      $arId = explode('.', $arReq[id]);
      $intCnt = count($arId);
      

      $this->arFile = array();
      for($i=0; $i<$intCnt; $i++)
      {
       if($i == ($intCnt-1)) $this->strId = $arId[$i];
       else       $this->arFile[] = $arId[$i];
      }

      $arInfo = $this->getXmlSql($xmlData, $arReq[opt]);
      return $arInfo;
     }

     public function getXmlSql($xml, $arOpt = array())
     {
      $strArName = implode('', $this->arFile);

      if(!$this->parser[$strArName])
      {
       $xml = $this->getXmlRead();
       $this->parser[$strArName] = new DOMDocument;
       $this->parser[$strArName]->loadXML($xml);
      }
      unset($arQuery);

      $arQuery = $this->parser[$strArName]->getElementsByTagName('query');

      if($arQuery)
      {
       foreach($arQuery as $q)
       {
        if($this->strId == $q->getAttribute('id'))
        {
         $type = $q->getAttribute('type');
         $sql = $q->getElementsByTagName('sql')->item(0)->nodeValue;
         $db = $q->getElementsByTagName('db')->item(0)->nodeValue;

         if($arOpt)
         {   
          $arWhere = array();
          $_arWhere = $q->getElementsByTagName('opt');
          foreach($_arWhere as $where)
          {  
           if(in_array($where->getAttribute('id'), $arOpt))
            $arWhere[] = $where->nodeValue;
          }
          $sql .= ' where '.implode(' and ', $arWhere);
         }  
         $sql .= ' '.$q->getElementsByTagName('etc')->item(0)->nodeValue;
        }
       }
      }
      return array($db, $sql, $type);
     }


     /* 관련 파일 또는 Acct를 불러옵니다. */
     private function getXmlRead()
     {
      /* 해당 XML파일을 이미 확인함 */
      $strArName = implode('', $this->arFile);

      $strXmlFile = XML_PWD.'/sql/'.$this->arFile[0].'/sql.'.implode('.', $this->arFile).'.xml';
      $strXmlData = $this->xmlData[$strArName];

      if($strXmlData) return $strXmlData;



      $fp = fopen($strXmlFile, "r");
      if($fp)
      {
       while (!feof($fp))
       {
          $strXmlData .= fread($fp, 1024);
       }
       fclose($fp);

       $this->xmlData[$strArName] = $strXmlData;
      }
      return $strXmlData;
     }
    }
    ?>


    Mysqli Query Class
    /*
    * 작성일 : 2007-04-04 최초작성자 : 김만희
    */


    class commonMi extends mysqli
    {
     private $dbHost, $dbUser, $dbPassword, $dbSchema, $xmlFilePath, $queryFilePath;
     private $csSqlxml, $objMyStmt;
     private $stmt, $m_result;
     private $gSTARTTIME = 0;
     private $gENDTIME = 0;
     private $gTOTALTIME=  0;
     private $csDebug;
     public $dbquerys;

     public function __construct($strConDb='')
     {
      $this->csSqlxml = new commonSqlxml;

      $this->xmlFilePath = XML_PWD.'/conf/conf.db.xml';
      $this->stmt = array();
      $this->dbquerys = array();

      if($strConDb) $this->connectInit($strConDb);

      $this->csDebug = new commonDebugger;
     }

     private function connectInit($strConDb)
     {
      $connectionID = (DB_CON == 'dev') ? 'dev::'.$strConDb : $strConDb;

      $this->_getDbInfo($connectionID);

      @parent::__construct($this->dbHost, $this->dbUser, $this->dbPassword, $this->dbSchema);

      if (mysqli_connect_error())
      {
       throw new exceptionConnect(mysqli_connect_error(), mysqli_connect_errno());
      }

     }

     public function __destruct()
     {
      if (!mysqli_connect_errno())   {
       @$this->stmt->close();
       $this->close();
       if(DEBUG == 11)
       {
        print_r($this->dbquerys);
       }

      }
     }

     private function _getDbInfo($connectionID)
     {
      if (!(file_exists($this->xmlFilePath))) return FALSE;

      $connections = simplexml_load_file($this->xmlFilePath);

      foreach($connections as $connection)
      {
       if ($connection['ID'] == $connectionID)
       {    
        $this->dbHost    = $connection->dbHost;
        $this->dbUser    = $connection->dbUser;
        $this->dbPassword = $connection->dbPassword;
        $this->dbSchema  = $connection->dbSchema;
       }
      }
     }

     public function query($arParam)
     {
      list($strConDb, $strSql, $type) = $this->csSqlxml->getSql($arParam);

      //if(!$this->stmt)
      $this->connectInit($strConDb);
      //$this->dbSchema
      $this->stmt = parent::stmt_init();
      $logsql = vsprintf(str_replace('?', '\'%s\'',$strSql), $arParam[val]);
      $this->stmt->prepare($strSql);

      $this->startWatch();

      if(count($arParam[val]))
      {
       $params = array(str_repeat('s', sizeof($arParam[val])));
       foreach($arParam[val] as $v)
       {
        $params[] = $v;
       }

       call_user_func_array(array($this->stmt, 'bind_param'),$params);
      }
      $this->m_result =$this->stmt->execute();


      $exectime = $this->stopWatch();
      array_push($this->dbquerys, $logsql);
      if(DEBUG == 21)
      {
       $this->csDebug->_setDebugQry($exectime, $logsql);
      }
      return $this->results;
     }

     public function getRow()
     {
      $this->stmt->store_result();
      $meta = $this->stmt->result_metadata();

      $fields = $meta->fetch_fields();

      foreach($fields as $k => $v)
      {
       $bindVarsArray[] = &$this->results[$v->name];
      }

      call_user_func_array(array($this->stmt, 'bind_result'), $bindVarsArray);

      if($this->stmt->fetch() != null)
      {
       foreach($this->results as $k=>$v)
       {
        $res[$k] = $v;
       }
       $this->stmt->free_result();

       return $res;
      } else {
       return null;
      }
     }

     public function getRows()
     {
      $this->stmt->store_result();
      $nCount = $this->stmt->field_count;

      $meta = $this->stmt->result_metadata();

      $fields = $meta->fetch_fields();

      foreach($fields as $k => $v)
      {

       $bindVarsArray[$v->name] = &$this->results[$v->name];
      }

      call_user_func_array(array($this->stmt, 'bind_result'), $bindVarsArray);

      $i=0;
      while($this->stmt->fetch())
      {

        foreach($bindVarsArray as $sKey => $sValue)
        {
         $aResult[$i][$sKey] = $sValue;
        }
        $i++;
      }

      return $aResult;

     }

     public function iquery($strSql)
     {
      $this->startWatch();
      $this->m_result =  parent::query($strSql);

      $exectime = $this->stopWatch();


      if(DEBUG == 11)
      {
       echo $strSql.' 
    '.@implode(',',$arParam[val]);
      } else if(DEBUG == 21)
      {
       $this->csDebug->_setDebugQry($exectime, $strSql.' 
    '.@implode(',',$arParam[val]));
      }


      if (!$this->m_result)   return 0; //throw new exceptionQuery(mysqli_error($this), mysqli_errno($this));

      return $this->m_result;
     }

     public function igetRow()
     {
      if (!$this->m_result) return null;

      return $this->m_result->fetch_assoc();
     }

     public function igetRows()
     {
      while ($row = mysqli_fetch_assoc($this->m_result))
      {
       $rows[] = $row;
      }
      return $rows;
     } 

     private function _getWatch()
     {
      list($foo,$bar)=explode(' ',microtime());
      $timer = $foo + $bar;
      unset($foo);
      unset($bar);
      return $timer;
     }

     /** Query 시작시간 **/
     private function startWatch()
     {
      $this->gSTARTTIME = 0;
      $this->gENDTIME = 0;

      $this->gSTARTTIME = $this->_getWatch();
     }

     /** Query 종료시간 **/
     private function stopWatch()
     {
      $this->gENDTIME = $this->_getWatch();
      $endtime = round($this->gENDTIME-$this->gSTARTTIME,5);
      $this->gTOTALTIME += $endtime;
      return $endtime;
     }

    }
    ?>


    사용  예제
    $m_db = new commonMi();
    $param = array(
    id => 'adm.fboard.fboardListByPage',
    opt => array($stype),
    val => array('%'.$sword.'%', $start, $offset)
    );

    $m_db->query($param);
    $rows = $m_db->getRows();

    print_r($rows);
    ?>

    설명이 필요하다면 다음과 같이 설명할 수 있습니다.

    개발자1 이 본인이 원하는 쿼리를 DBA 또는 본인이 직접 작성하여, XML에 저장한 후
    해당 XML의 고유한 ID값을 호출한 후 mysqli를 이용해 쿼리를 실행하게 되는 형식입니다.


    위의 프레임워크(??)는 현재 버전으로 따진다면 0.1정도의 버전이며,
    현재 실험중에 있슴..

    위의 프레임웍은 개발자혼자서 DB까지 관리한다고 하더라도 모든 SQL문을 XML로 관리하기 때문에
    관리의 이점이 뛰어난게 장점이며, 자체 테스트 결과 상당히 빠른 속도의 결과를 보였슴.

    하지만 역시나 게으르거나 환경적응을 못한다면 도전해볼만하지 못할수도 있습니다.

     

    P.S 환경설정부분의 소스들이 포함되어 본인이 원할 경우에 몇가지를 가독후 수정해주셔야 할듯합니다.
    바로 가져다가 쓰시면 안된다는 거죠.. ^^;;

  • 트랙백 0 : 덧글 2