<?php
/* SVN FILE: $Id: PostgreSQL.php 330 2008-05-11 01:12:14Z bb_yujiro $ */
/**
 * rkt_manipulation.php PostgreSQLドライバ
 *
 * PHP versions 5
 *
 *      hitSuji : Social Network Service <http://rakuto.net/rktSNS/>
 *      Copyright (c) 2007 Yujiro Takahashi
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @filesource
 * @package         hitSuji
 * @copyright       Copyright (c) 2007 Yujiro Takahashi
 * @link            http://rakuto.net/
 * @author          Yujiro Takahashi <yujiro@rakuto.net>
 * @version         $Revision: 330 $
 * @modifiedby      $LastChangedBy: bb_yujiro $
 * @lastmodified    $Date: 2008-05-11 10:12:14 +0900 (日, 11 5 2008) $
 * @license         http://opensource.org/licenses/mit-license.php The MIT License
 */

/**
 * PostgreSQLドライバクラス
 *
 * @category        Model::Manipulation
 * @package         hitSuji
 * @copyright       Copyright (c) 2007 Yujiro Takahashi
 * @link            http://rakuto.net/
 * @author          Yujiro Takahashi <yujiro@rakuto.net>
 * @version         $Revision: 330 $
 * @modifiedby      $LastChangedBy: bb_yujiro $
 * @lastmodified    $Date: 2008-05-11 10:12:14 +0900 (日, 11 5 2008) $
 * @license         http://opensource.org/licenses/mit-license.php The MIT License
 */
class Model_Manip_PostgreSQL
{
    /**
     * DB接続オジェクト
     * @var object
     */
    private $_objdb = null;

    /**
     * テーブル名
     * @var string
     */
    private $_tbl_name = '';

    /**
     * プライマリキー
     * @var array
     */
    private $_primary = array();

    /**
     * コンストラクタ
     *
     * @access public
     * @param string $tbl_name テーブル名
     */
    public function __construct($tbl_name='')
    {
        $this->_objdb = RKT_DB::getInstance();

        $this->_tbl_name = $tbl_name;
    }

    /**
     * テーブル名の設定
     *
     * @access public
     * @param string $tbl_name
     * @return void
     */
    public function setTableName($tbl_name)
    {
        $this->_tbl_name = $tbl_name;
    }

    /**
     * プライマリキーの取得
     *
     * @access public
     * @return string
     */
    public function getPrimaryKey()
    {
        return $this->_primary['key'];
    }

    /**
     * 全テーブル名の取得
     *
     * @access public
     * @return array
     */
    public function getTables()
    {
        $sql =
            'SELECT '.
                'tablename '.
            'FROM '.
                'pg_tables '.
            'WHERE '.
                "NOT tablename LIKE 'pg%'";
        $stmt = $this->_objdb->prepare($sql); 
        $stmt->execute(); 
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $list = array();
        foreach ($result as $value){
            $list[] = $value['tablename'];
        }

        return $list;
    }

    /**
     * 項目情報の解析
     *
     * @access public
     * @param array $skip
     * @return array
     */
    public function parseColumns($skip=array())
    {
        $sql=
            'SELECT '.
                'att.attname,'.
                'typ.typname,'.
                'att.attlen,'.
                'att.atthasdef,'.
                'att.attnotnull,'.
                'def.adsrc as defval,'.
                'att.atttypmod,'.
                'att.attnum,'.
                'idx.indkey '.
            'FROM '.
                'pg_type typ,'.
                'pg_class cls,'.
                'pg_attribute att '.
                'LEFT JOIN pg_attrdef def '.
                'ON (att.attrelid=def.adrelid AND '.
                    'att.attnum=def.adnum),'.
                'pg_index idx '.
            'WHERE '.
                'cls.oid = att.attrelid AND '.
                'cls.oid = idx.indrelid AND '.
                'typ.oid = att.atttypid AND '.
                'cls.relname = '.$this->_objdb->quote($this->_tbl_name).' AND '.
                'idx.indisprimary = true AND '.
                'att.attnum > 0 '.
            'ORDER BY '.
                'att.attnum';
        $stmt = $this->_objdb->prepare($sql); 
        $stmt->execute(); 
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $validates = array();
        foreach ($result as $value){
            $key  = $value['attname'];
            $parse = $this->_parseType($value['typname'],$key,$value['atttypmod']);
            $infos = array(
                'type'=>    $parse['type'],
                'pdo_type'=>$parse['pdo_type'],
                'option'=>  $parse['option'],
                'default'=> $this->_parseDefaultValue($value['defval']),
                'required'=>$this->_parseRequired($value['attnotnull']),
                'effect'=>  array('RKT_validate', $parse['effect']),
            );

            /* プライマリキーは別扱い */
            if ($value['attnum'] == $value['indkey']){
                $this->_primary = array(
                    'key'=>  $key,
                    'info'=> $infos
                );
            } else {
                if (!in_array($key,$skip)){
                    $validates[$key] = $infos;
                }
            } // if (!$this->catch_primary_key($value['Key']))
        }

        return $validates;
    }

    /**
     * フィールドの型を解析
     *
     * @access private
     * @param string $subject
     * @param string $option
     * @param integer $size
     * @return array
     */
    private function _parseType($subject, $field, $size)
    {
        $type     = 'string';
        $pdo_type = 'PDO::PARAM_STR';
        $option   = null;
        $effect   = 'multiStripTags';
        $size     = $size - 4;
        if ($size <= 0){
            $size = 8000;
        }

        /* 型名から設定 */
        if (preg_match('/varchar/i', $subject)){
            $type = 'string';
            $option = array(
                'max_length'=>$size
            );
        } else if (preg_match('/int/i', $subject)){
            $type = 'number';
            $pdo_type = 'PDO::PARAM_INT';
        } else if (preg_match('/text/i', $subject)){
            $type = 'string';
            $option = array(
                'max_length'=>$size
            );
            $effect   = 'multiStripJavaScript';
        } else if (preg_match('/date/i', $subject)){
            $type = 'date';
            $option = array(
                'format'=> '%Y-%n-%d'
            );
        } else if (preg_match('/timestamp/i', $subject)){
            $type = 'date';
            $option = array(
                'format'=> '%Y-%n-%d %H:%i:%s'
            );
        } else if (preg_match('/float/i', $subject)){
            $type = 'number';
            $pdo_type = 'PDO::PARAM_INT';
            $option = array(
                'decimal'=>'.'
            );
        } else if (preg_match('/double/i', $subject)){
            $type = 'number';
            $pdo_type = 'PDO::PARAM_INT';
            $option = array(
                'decimal'=>'.'
            );
        } else if (preg_match('/bytea/i', $subject)){
            $type = 'string';
            $pdo_type = 'PDO::PARAM_LOB';
            $option = array(
                'max_length'=>$size
            );
        }
        
        /* フィールド名から設定 */
        if (preg_match('/email/i', $field)){
            $type = 'email';
        } else if (preg_match('/url/i', $field)){
            $type = 'uri';
        } else if (preg_match('/^html/i', $field)){
            $type = 'string';
            $option = array(
                'max_length'=>$size
            );
            $effect   = 'multiStripSlashes';
        } else if (preg_match('/postal/i', $field)){
            $type = 'string';
            $option = array(
                'format'=>'\d+[-]*\d+'
            );
        } else if (preg_match('/phone/i', $field)){
            $type = 'string';
            $option = array(
                'format'=>'\d+[-]*\d+[-]*\d+'
            );
        } else if (preg_match('/fax/i', $field)){
            $type = 'string';
            $option = array(
                'format'=>'\d+[-]*\d+[-]*\d+'
            );
        } else if (preg_match('/password/i', $field)){
            $type = 'string';
            $option = array(
                'format'=> '\w+',
                'min_length'=>4,
                'max_length'=>$size
            );
        }
        
        return array('type'=>$type, 'pdo_type'=>$pdo_type, 'option'=>$option, 'effect'=>$effect);
    }

    /**
     * 必須項目設定の解析
     *
     * @access private
     * @param string $subject
     * @return boolean
     */
    private function _parseRequired($subject)
    {
        $pg2boolean = array(
            't'=> true,
            'f'=> false            
        );

        return $pg2boolean[$subject];
    }

    /**
     * 初期値の解析
     *
     * @access private
     * @param string $value
     * @return string
     */
    private function _parseDefaultValue($value)
    {
        $pos = strpos($value, "'::");
        if ($pos !== false){
            $value = substr($value, 1, $pos);
        }
        return $value;
    }
} // Model_Manip_PostgreSQLの終了
?>