Source for file Ethna_DB_PEAR.php

Documentation is available at Ethna_DB_PEAR.php

  1. <?php
  2. // vim: foldmethod=marker
  3. /**
  4.  *  Ethna_DB_PEAR.php
  5.  *
  6.  *  @author     Masaki Fujimoto <fujimoto@php.net>
  7.  *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
  8.  *  @package    Ethna
  9.  *  @version    $Id$
  10.  */
  11. require_once 'DB.php';
  12.  
  13. // {{{ Ethna_DB_PEAR
  14. /**
  15.  *  Ethna_DBクラスの実装(PEAR版)
  16.  *
  17.  *  @author     Masaki Fujimoto <fujimoto@php.net>
  18.  *  @access     public
  19.  *  @package    Ethna
  20.  */
  21. class Ethna_DB_PEAR extends Ethna_DB
  22. {
  23.     // {{{ properties
  24.     /**#@+
  25.      *  @access private
  26.      */
  27.  
  28.     /** @var    object  DB              PEAR DBオブジェクト */
  29.     var $db;
  30.  
  31.     /** @var    array   トランザクション管理スタック */
  32.     var $transaction array();
  33.  
  34.  
  35.     /** @var    object  Ethna_Logger    ログオブジェクト */
  36.     var $logger;
  37.  
  38.     /** @var    object  Ethna_AppSQL    SQLオブジェクト */
  39.     var $sql;
  40.  
  41.     /** @var    string  DBタイプ(mysql, pgsql...) */
  42.     var $type;
  43.  
  44.     /** @var    string  DSN */
  45.     var $dsn;
  46.  
  47.     /** @var    array   DSN (DB::parseDSN()の返り値) */
  48.     var $dsninfo;
  49.  
  50.     /** @var    bool    持続接続フラグ */
  51.     var $persistent;
  52.  
  53.     /**#@-*/
  54.     // }}}
  55.  
  56.     // {{{ Ethna_DBクラスの実装
  57.     // {{{ Ethna_DB_PEAR
  58.     /**
  59.      *  Ethna_DB_PEARクラスのコンストラクタ
  60.      *
  61.      *  @access public
  62.      *  @param  object  Ethna_Controller    &$controller    コントローラオブジェクト
  63.      *  @param  string  $dsn                                DSN
  64.      *  @param  bool    $persistent                         持続接続設定
  65.      */
  66.     function Ethna_DB_PEAR(&$controller$dsn$persistent)
  67.     {
  68.         parent::Ethna_DB($controller$dsn$persistent);
  69.  
  70.         $this->db null;
  71.         $this->logger =$controller->getLogger();
  72.         $this->sql =$controller->getSQL();
  73.  
  74.         $this->dsninfo DB::parseDSN($dsn);
  75.         $this->dsninfo['new_link'true;
  76.         $this->type $this->dsninfo['phptype'];
  77.     }
  78.     // }}}
  79.  
  80.     // {{{ connect
  81.     /**
  82.      *  DBに接続する
  83.      *
  84.      *  @access public
  85.      *  @return mixed   0:正常終了 Ethna_Error:エラー
  86.      */
  87.     function connect()
  88.     {
  89.         $this->db =DB::connect($this->dsninfo$this->persistent);
  90.         if (DB::isError($this->db)) {
  91.             $error Ethna::raiseError('DB Connection Error: %s',
  92.                 E_DB_CONNECT,
  93.                 $this->db->getUserInfo());
  94.             $error->addUserInfo($this->db);
  95.             $this->db null;
  96.             return $error;
  97.         }
  98.  
  99.         return 0;
  100.     }
  101.     // }}}
  102.  
  103.     // {{{ disconnect
  104.     /**
  105.      *  DB接続を切断する
  106.      *
  107.      *  @access public
  108.      */
  109.     function disconnect()
  110.     {
  111.         if ($this->isValid(== false{
  112.             return;
  113.         }
  114.         $this->db->disconnect();
  115.     }
  116.     // }}}
  117.  
  118.     // {{{ isValid
  119.     /**
  120.      *  DB接続状態を返す
  121.      *
  122.      *  @access public
  123.      *  @return bool    true:正常 false:エラー
  124.      */
  125.     function isValid()
  126.     {
  127.         if (is_null($this->db)
  128.             || is_resource($this->db->connection== false{
  129.             return false;
  130.         else {
  131.             return true;
  132.         }
  133.     }
  134.     // }}}
  135.  
  136.     // {{{ begin
  137.     /**
  138.      *  DBトランザクションを開始する
  139.      *
  140.      *  @access public
  141.      *  @return mixed   0:正常終了 Ethna_Error:エラー
  142.      */
  143.     function begin()
  144.     {
  145.         if (count($this->transaction0{
  146.             $this->transaction[true;
  147.             return 0;
  148.         }
  149.  
  150.         $r $this->query('BEGIN;');
  151.         if (Ethna::isError($r)) {
  152.             return $r;
  153.         }
  154.         $this->transaction[true;
  155.  
  156.         return 0;
  157.     }
  158.     // }}}
  159.  
  160.     // {{{ rollback
  161.     /**
  162.      *  DBトランザクションを中断する
  163.      *
  164.      *  @access public
  165.      *  @return mixed   0:正常終了 Ethna_Error:エラー
  166.      */
  167.     function rollback()
  168.     {
  169.         if (count($this->transaction== 0{
  170.             return 0;
  171.         }
  172.  
  173.         // ロールバック時はスタック数に関わらずトランザクションをクリアする
  174.         $r $this->query('ROLLBACK;');
  175.         if (Ethna::isError($r)) {
  176.             return $r;
  177.         }
  178.         $this->transaction array();
  179.  
  180.         return 0;
  181.     }
  182.     // }}}
  183.  
  184.     // {{{ commit
  185.     /**
  186.      *  DBトランザクションを終了する
  187.      *
  188.      *  @access public
  189.      *  @return mixed   0:正常終了 Ethna_Error:エラー
  190.      */
  191.     function commit()
  192.     {
  193.         if (count($this->transaction== 0{
  194.             return 0;
  195.         else if (count($this->transaction1{
  196.             array_pop($this->transaction);
  197.             return 0;
  198.         }
  199.  
  200.         $r $this->query('COMMIT;');
  201.         if (Ethna::isError($r)) {
  202.             return $r;
  203.         }
  204.         array_pop($this->transaction);
  205.  
  206.         return 0;
  207.     }
  208.     // }}}
  209.  
  210.     // {{{ getMetaData
  211.     /**
  212.      *  テーブル定義情報を取得する
  213.      *
  214.      *  @access public
  215.      *  @param  string  $table  テーブル名
  216.      *  @return mixed   array: PEAR::DBに準じたメタデータ Ethna_Error::エラー
  217.      */
  218.     function &getMetaData($table)
  219.     {
  220.         $def =$this->db->tableInfo($table);
  221.         if (is_array($def=== false{
  222.             return $def;
  223.         }
  224.  
  225.         foreach (array_keys($defas $k{
  226.             $def[$karray_map('strtolower'$def[$k]);
  227.  
  228.             // type
  229.             $type_map array(
  230.                 'int'       => array(
  231.                     'int''integer''^int\(?[0-9]\+''^serial''[a-z]+int$',
  232.                 ),
  233.                 'boolean'   => array(
  234.                     'bit''bool''boolean',
  235.                 ),
  236.                 'datetime'  => array(
  237.                     'timestamp''datetime',
  238.                 ),
  239.             );
  240.             foreach ($type_map as $convert_to => $regex{
  241.                 foreach ($regex as $r{
  242.                     if (preg_match('/'.$r.'/'$def[$k]['type'])) {
  243.                         $def[$k]['type'$convert_to;
  244.                         break 2;
  245.                     }
  246.                 }
  247.             }
  248.  
  249.             // flags
  250.             $def[$k]['flags'explode(' '$def[$k]['flags']);
  251.             switch ($this->type{
  252.             case 'mysql':
  253.                 // auto_increment があれば sequence
  254.                 if (in_array('auto_increment'$def[$k]['flags'])) {
  255.                     $def[$k]['flags']['sequence';
  256.                 }
  257.                 break;
  258.             case 'pgsql':
  259.                 // nextval があれば sequence
  260.                 foreach ($def[$k]['flags'as $f{
  261.                     if (strpos($f'nextval'!== false{
  262.                         $def[$k]['flags']['sequence';
  263.                         break;
  264.                     }
  265.                 }
  266.                 break;
  267.             case 'sqlite':
  268.                 // integer, primary key ならば auto_increment を追加
  269.                 if ($def[$k]['type'== 'int'
  270.                     && in_array('primary_key'$def[$k]['flags'])) {
  271.                     $def[$k]['flags']['sequence';
  272.                 }
  273.                 break;
  274.             }
  275.         }
  276.  
  277.         return $def;
  278.     }
  279.     // }}}
  280.     // }}}
  281.  
  282.     // {{{ Ethna_AppObject連携のための実装
  283.     // {{{ getType
  284.     /**
  285.      *  DBタイプを返す
  286.      *
  287.      *  @access public
  288.      *  @return string  DBタイプ
  289.      */
  290.     function getType()
  291.     {
  292.         return $this->type;
  293.     }
  294.     // }}}
  295.  
  296.     // {{{ query
  297.     /**
  298.      *  クエリを発行する
  299.      *
  300.      *  @access public
  301.      *  @param  string  $query  SQL文
  302.      *  @return mixed   DB_Result:結果オブジェクト Ethna_Error:エラー
  303.      */
  304.     function &query($query)
  305.     {
  306.         return $this->_query($query);
  307.     }
  308.     // }}}
  309.  
  310.     // {{{ getNextId
  311.     /**
  312.      *  直後のINSERTに使うIDを取得する
  313.      *  (pgsqlのみ対応)
  314.      *
  315.      *  @access public
  316.      *  @return mixed   int
  317.      */
  318.     function getNextId($table_name$field_name)
  319.     {
  320.         if ($this->isValid(== false{
  321.             return null;
  322.         else if ($this->type == 'pgsql'{
  323.             $seq_name sprintf('%s_%s'$table_name$field_name);
  324.             $ret $this->db->nextId($seq_name);
  325.             return $ret;
  326.         }
  327.  
  328.         return null;
  329.     }
  330.     // }}}
  331.  
  332.     // {{{ getInsertId
  333.     /**
  334.      *  直前のINSERTによるIDを取得する
  335.      *  (mysql, sqliteのみ対応)
  336.      *
  337.      *  @access public
  338.      *  @return mixed   int:直近のINSERTにより生成されたID null:未サポート
  339.      */
  340.     function getInsertId()
  341.     {
  342.         if ($this->isValid(== false{
  343.             return null;
  344.         else if ($this->type == 'mysql'{
  345.             return mysql_insert_id($this->db->connection);
  346.         else if ($this->type == 'sqlite'{
  347.             return sqlite_last_insert_rowid($this->db->connection);
  348.         }
  349.  
  350.         return null;
  351.     }
  352.     // }}}
  353.  
  354.     // {{{ fetchRow
  355.     /**
  356.      *  DB_Result::fetchRow()の結果を整形して返す
  357.      *
  358.      *  @access public
  359.      *  @return int     更新行数
  360.      */
  361.     function &fetchRow(&$res$fetchmode DB_FETCHMODE_DEFAULT$rownum null)
  362.     {
  363.         $row =$res->fetchRow($fetchmode$rownum);
  364.         if (is_array($row=== false{
  365.             return $row;
  366.         }
  367.  
  368.         if ($this->type === 'sqlite'{
  369.             // "table"."column" -> column
  370.             foreach ($row as $k => $v{
  371.                 unset($row[$k]);
  372.                 if (($f strstr($k'.')) !== false{
  373.                     $k substr($f1);
  374.                 }
  375.                 if ($k{0=== '"' && $k{strlen($k)-1=== '"'{
  376.                     $k substr($k1-1);
  377.                 }
  378.                 $row[$k$v;
  379.             }
  380.         }
  381.  
  382.         return $row;
  383.     }
  384.     // }}}
  385.  
  386.     // {{{ affectedRows
  387.     /**
  388.      *  直近のクエリによる更新行数を取得する
  389.      *
  390.      *  @access public
  391.      *  @return int     更新行数
  392.      */
  393.     function affectedRows()
  394.     {
  395.         return $this->db->affectedRows();
  396.     }
  397.     // }}}
  398.  
  399.     // {{{ quoteIdentifier
  400.     /**
  401.      *  dbのtypeに応じて識別子をquoteする
  402.      *  (配列の場合は各要素をquote)
  403.      *
  404.      *  @access protected
  405.      *  @param  mixed   $identifier array or string
  406.      */
  407.     function quoteIdentifier($identifier)
  408.     {
  409.         if (is_array($identifier)) {
  410.             foreach (array_keys($identifieras $key{
  411.                 $identifier[$key$this->quoteIdentifier($identifier[$key]);
  412.             }
  413.             return $identifier;
  414.         }
  415.             
  416.         switch ($this->type{
  417.         case 'mysql':
  418.             $ret '`' $identifier '`';
  419.             break;
  420.         case 'pgsql':
  421.         case 'sqlite':
  422.         default:
  423.             $ret '"' $identifier '"';
  424.             break;
  425.         }
  426.         return $ret;
  427.     }
  428.     // }}}
  429.     // }}}
  430.  
  431.     // {{{ Ethna_DB_PEAR独自の実装
  432.     // {{{ sqlquery
  433.     /**
  434.      *  SQL文指定クエリを発行する
  435.      *
  436.      *  @access public
  437.      *  @param  string  $sqlid      SQL-ID(+引数)
  438.      *  @return mixed   DB_Result:結果オブジェクト Ethna_Error:エラー
  439.      */
  440.     function &sqlquery($sqlid)
  441.     {
  442.         $args func_get_args();
  443.         array_shift($args);
  444.         $query $this->sql->get($sqlid$args);
  445.  
  446.         return $this->_query($query);
  447.     }
  448.     // }}}
  449.  
  450.     // {{{ sql
  451.     /**
  452.      *  SQL文を取得する
  453.      *  
  454.      *  @access public
  455.      *  @param  string  $sqlid      SQL-ID
  456.      *  @return string  SQL文
  457.      */
  458.     function sql($sqlid)
  459.     {
  460.         $args func_get_args();
  461.         array_shift($args);
  462.         $query $this->sql->get($sqlid$args);
  463.  
  464.         return $query;
  465.     }
  466.     // }}}
  467.  
  468.     // {{{ lock
  469.     /**
  470.      *  テーブルをロックする
  471.      *
  472.      *  @access public
  473.      *  @param  mixed   ロック対象テーブル名
  474.      *  @return mixed   DB_Result:結果オブジェクト Ethna_Error:エラー
  475.      */
  476.     function lock($tables)
  477.     {
  478.         $this->message null;
  479.  
  480.         $sql "";
  481.         foreach (to_array($tablesas $table{
  482.             if ($sql != ""{
  483.                 $sql .= ", ";
  484.             }
  485.             $sql .= "$table WRITE";
  486.         }
  487.  
  488.         return $this->query("LOCK TABLES $sql");
  489.     }
  490.     // }}}
  491.  
  492.     // {{{ unlock
  493.     /**
  494.      *  テーブルのロックを解放する
  495.      *
  496.      *  @access public
  497.      *  @return mixed   DB_Result:結果オブジェクト Ethna_Error:エラー
  498.      */
  499.     function unlock()
  500.     {
  501.         $this->message null;
  502.         return $this->query("UNLOCK TABLES");
  503.     }
  504.     // }}}
  505.  
  506.     // {{{ _query
  507.     /**
  508.      *  クエリを発行する
  509.      *
  510.      *  @access private
  511.      *  @param  string  $query  SQL文
  512.      *  @return mixed   DB_Result:結果オブジェクト Ethna_Error:エラー
  513.      */
  514.     function &_query($query)
  515.     {
  516.         $this->logger->log(LOG_DEBUG"$query");
  517.         $r =$this->db->query($query);
  518.         if (DB::isError($r)) {
  519.             if ($r->getCode(== DB_ERROR_ALREADY_EXISTS{
  520.                 $error Ethna::raiseNotice('Unique Constraint Error SQL[%s]',
  521.                     E_DB_DUPENT,
  522.                     $query,
  523.                     $this->db->errorNative(),
  524.                     $r->getUserInfo());
  525.             else {
  526.                 $error Ethna::raiseError('Query Error SQL[%s] CODE[%d] MESSAGE[%s]',
  527.                     E_DB_QUERY,
  528.                     $query,
  529.                     $this->db->errorNative(),
  530.                     $r->getUserInfo());
  531.             }
  532.             return $error;
  533.         }
  534.         return $r;
  535.     }
  536.     // }}}
  537.     // }}}
  538. }
  539. // }}}
  540. ?>

Documentation generated on Fri, 11 Nov 2011 03:59:40 +0900 by phpDocumentor 1.4.3