Source for file PEAR.php

Documentation is available at PEAR.php

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

Documentation generated on Fri, 11 Nov 2011 03:58:47 +0900 by phpDocumentor 1.4.3