ロゴ
HOME > CakePHP > CakePHP + Oracle で開発する場合のまとめ

CakePHP + Oracle で開発する場合のまとめ

2015年08月07日

先ず、現行のCakephp2ではOracleに対応していません。CakePHP3に関しても詳細に調べてはいませんが、おそらく対応していません。

そもそもWEB系のデータベースにOracleを使うという行為自体が既に間違っていると思います。管理側のパッケージソフトウエアがOracleで、どうしてもOracleで開発を進めなくてはならない、となるのであれば、一度MySQLやポスグレに落とし込んだデータをパッケージ側で取り込み、処理をするという形がベストだと思います。

それほど融通が効きません。

ドライバーに関して

公式にはもちろん用意されていません。CakePHP1の頃はあったようですが、これは使えません。ですので、有志が作成したドライバーを探します。日本サイトには有りませんので、海外サイトを探す事になります。cakephp oracle とでも検索していくと幾つか見つかると思います。どれもほぼ使えると思って構いませんが、出来るだけ公開日が最近のものを見つけて下さい。

あえてダウンロード先は記載しません。

ドライバーの配置

img

ドライバーさえ手に入れば、後は他のドライバーと同じ場所に配置します。

database.phpの設定
	public $default = array(
		'datasource' => 'Database/Oracle',
		'driver' => 'oracle',
		'connect' => 'oci_pconnect',
		'persistent' => false,
		'host' => 'localhost',
		'login' => '***************',
		'password' => '***************',
		'database' => '***************',
		'prefix' => '',
		'port' => '1523',
		'charset' => 'AL32UTF8',
	);

Portと文字コード設定を忘れずに。

Model
App::uses('Model', 'Model');
class Table extends Model {
  public $name        = 'Table';
	public $useTable    = 'ORACLE_TABLE';

  
  public function transactionBegin(){
    $dataSource = $this->getDataSource();
    $dataSource->execute('START TRANSACTION');
  }

  public function transactionCommit(){
    $dataSource = $this->getDataSource();
    $dataSource->execute('COMMIT');
  }

  public function transactionRollback(){
    $dataSource = $this->getDataSource();
    $dataSource->execute('ROLLBACK');
  }
}

特に変わった事は有りません。MySQLなんかと同じようにModelを作ります。

Selectする
$data = $this->Table->find('first', $conditions );

単純に呼び出すだけならCakePHPの普通の構文で良いのですが、カラム名が長かったり、WHEREに設定する文字列が長かったりしてSQL文自体が長くなるとエラーを吐きます。

ORA-01704: 文字列リテラルが長すぎます

なので、*で全フィールドを呼び出すのではなく、必要なフィールドだけを指定したり、別名を使って短くするなど工夫が必要な場合も有ります。後述するインサートやアップデート文でも同じですね。

インサートとアップデート

文字の長さを制御(oracleは4,000バイトまで)出来れば、Cakephpのsave文でいけますが、問題は日時。

CakePHPはcreatedやmodifiedというカラムを作っておけば、意図せずとも日時をインサートしてくれますが、oracleはもちろん、そんな事はしてくれません。

to_date('2015-01-01', 'yyyy-mm-dd HH24:MI:SS')

oracleのdate型のカラムに時間も含めて設定する場合は、上記のようなSQLが必要です。

ならquery使えばいいんじゃ?と先ずは考えます。

App::import('Model', 'ConnectionManager');
$db = ConnectionManager::getDataSource('default');
$sql = "INSERT *************************";
$result = $db->query($sql);

上記はCakephpのDB接続を呼び出し、直のSQLを発行する為の書き方です。こう書くとCakephpの規則から外れ、いつも書くSQL文を実行する事が出来ます。

ところが問題が有り、プリベアードステートメントが使えないのです。

$sql = "SELECT * FROM table WHERE id=?";
$result = $db->query($sql,array(1) );

例えば上記のように書くとプリベアードステートメントで処理されますが、これがOracleの場合は効きません。いえ、Oracle自体は問題無いのですが、ドライバーがそれに対応していません。有志作成のものをかなりの数、試行しましたが、どれもダメでした。自分でカスタムしようとも考えましたが、そもそもOracleなんてもの自体が慣れていないので諦めました。

じゃどうするか

ユニークな値を格納するフィールドを作っておき、何も考えずsaveします。その後、そのユニークな値の列の日付カラムをquery文でアップデートする、という手です。なぜプリベアードステートメントを使いたいか、というのはSQLを相応に触っている方であれば理解出来る事なので説明は省きます。

暗号化

先ず、cakephpには暗号化関数が用意されていますので、VARCHAR2(2000)などにしておけば格納する事は可能です。ですが、問題は4,000バイト制限。暗号化された文字って長いんですよ。なので、安易にそのまま使うと、文字なげーよ、ってエラーを吐いて寄越します。なので、前項の後からアップデートする、という手を使うなど工夫します。

但し、これはあくまでCakephpで運用するOracleに限っての話しなので、そもそもOracleを指定されるという事は、基幹システムはWEB上ではなくソフトウエアか何かなのです。そっちではCakephp?はぁ?って事なので、状況如何によってはCakephpの暗号化は使えません。

その場合はOracle側でFunctionを作り、Oracle自体で暗号化するって事になるので、それに見合ったSQLをqueryで実行します。

まとめ

ざくざくと書きましたが、その他にもた~~くさんの問題が出てきます。

とりあえず、CakePHP + Oracleなんてケースは稀でしょうから、そんな案件が来たら「無理ですよ?」と言うのが正しいかと思います。