Phalcon\Db のデータベースデータタイプ対応

  • KJ
  • 2014/09/11

Phalcon でデータベースマイグレーションを行う時に BIGINT とか ENUM とかのデータタイプが指定できなかったのでできるように Phalcon のデータベース関連のクラスを更新しました。

実装

Phalcon\Db\ColumnInterface

Phalcon\Db\ColumnInterfacegetTypeReferencegetTypeValues メソッドを追加します。

Phalcon\Db\ColumnInterface::getTypeReference

getTypeReference は Phalcon で定義されているデータベースタイプの参照値を取得するものになります。

Phalcon\Db\ColumnInterface::getTypeValues

getTypeValuesENUM 等の定義値を取得するためのものになります。

Phalcon\Db\Column

getTypeReferencegetTypeValues の実装になります。

それぞれの値を保持するよう protected 変数を準備し、取得できるように支持します。

protected _typeReference { get };

protected _typeValues { get };
  • __construct

    コンストラクタでは引数に typeReferencetypeValues の定義があったら変数に設定するようにします。

    typeReference の定義がない場合はどのタイプでもないこを示すために -1 を設定します。

    if fetch typeReference, definition["typeReference"] {
    let this->_typeReference = typeReference;
    } else {
    let this->_typeReference = -1;
    }
    
    if fetch typeValues, definition["typeValues"] {
    let this->_typeValues = typeValues;
    }
    
  • __set_state

    __set_state メソッドでもそれぞれのタイプの定義があったら設定するようにします。

    if fetch columnTypeReference, data["_typeReference"] {
    let definition["typeReference"] = columnTypeReference;
    } else {
    let definition["typeReference"] = -1;
    }
    
    if fetch columnTypeValues, data["_typeValues"] {
    let definition["typeValeus"] = columnTypeValues;
    }
    

Phalcon\Db\Diaalect\Mysql

MySQL のクラスでは getTypeReferencegetTypeValues および getType の値を使用して SQL を組み立てるように変更します。

はじめにデータタイプの取得処理を次のように変更します。

let columnSql = "";
let type = column->getType();
if typeof type == "string" {
  let columnSql .= type;
  let type = column->getTypeReference();
}

getType で取得したデータタイプが文字列だった場合はその値を columnSql に追記し、新たに getTypeReference で取得した値をデータタイプとします。

次に各データタイプの処理をします。

Column::TYPE_INTEGER の場合は次のようになります。

if empty columnSql {
  let columnSql .= "INT";
}
let columnSql .= "(" . column->getSize() . ")";

columnSql が空だった場合は INT を追記した後サイズを追記します。 columnSql が空でなかった場合はサイズの追記のみ行います。 (データタイプを取得した段階でタイプ文字列が追記されているから)

他のデータタイプも同じように変更します。

最後にどのデータタイプでもない場合は処理を次のように変更します。

if empty columnSql {
  throw new Exception("Unrecognized MySQL data type");
}

let typeValues = column->getTypeValues();
if !empty typeValues {
  if typeof typeValues == "array" {
    var value, valueSql;
    let valueSql = "";
    for value in typeValues {
      let valueSql .= "\"" . addcslashes(value, "\"") . "\", ";
    }
    let columnSql .= "(" . substr(valueSql, 0, -2) . ")";
  } else {
    let columnSql .= "(\"" . addcslashes(typeValues, "\"") . "\")";
  }
}

getTypeValues で値が取得できた場合は括弧内に定義するようにして columnSql に追記します。

Phalcon\Db\Diaalect\Postgresql

Phalcon\Db\Diaalect\Sqlite

Phalcon\Db\Diaalect\Postgresql, Phalcon\Db\Diaalect\Sqlite も MySQL クラスと同じように修正します。


これで Phalcon のデータベース関連のクラスでデータベース提供しているデータタイプが扱えるようになります。

サンプル

実際に使用するときは次のように指定します。

new Phalcon\Db\Column('id', array(
  'type' => 'BIGINT',
  'typeReference' => Column::TYPE_INTEGER,
  'size' => 20,
  'unsigned' => true,
  'notNull' => false
))

Phalcon\Db\Column にてタイプに文字列でデータタイプを指定します。 typeReference には Phalcon でのデータタイプを指定します。

上記の場合は typeReferenceColumn::TYPE_INTEGER を指定してあるので id フィールドは基本的には Column::TYPE_INTEGER と同じ挙動をしてデータタイプの出力として INT ではなく BIGINT を使うようになります。

ENUM 等を定義する時は次のようになります。

new Column('types', array(
  'type' => 'ENUM',
  'typeValues' => array('user', 'client'),
  'default' => 'user',
  'notNull' => true,
  'after' => 'id',
))

タイプの ENUM を指定して、typeValues にリストを定義します。 default を使用して既定値の定義も可能です。