2012.
10.
13
16:59:57
CakePHPで作られているシステムがありましてね。
そのシステムに新しい機能を追加しているのですが、
既存の別システムのテーブルを参照する必要がでてきました。
このテーブルが複合主キーのテーブルだったのです。
複合主キーのテーブルってのは、例えば「先生テーブル」ってな名前で
主キーが「学校ID」と「先生ID」みたいなテーブルね。
ん(--?
複合主キーのテーブルってCakePHPでどーやって扱うの(--?
と思ったのでえっちらおっちら調べてみたのですが、
CakePHPは複合主キーをサポートしません。
って書いてありました(--;
2.x系だったけど多分1.3系も一緒でしょ。。
……○ね!(#゚д゚)
……○にやがれ!(#゚д゚)
検索系はquery()メソッドでSQL直打ちすりゃーいーやと割り切ったけど、
更新系は流石にSQL組みたくないな~(-A-;)
だからフレームワーク嫌いなんだよ、とぶちぶち愚痴りながら調べていたら
なんか素敵なことやってる方がいらっしゃいました(人´∀`)
CakePHPで複合主キーのテーブルを更新するためのモデルを
作ってくださってる方がいらっしゃいましたよ。
こんなのφ(*´ェ`*)
CakePHPで複合主キーのテーブルを更新するためのモデル(抽象クラス)
これを参考に……と言うかほぼ丸パクリしてみたのですが、
私の環境(CakePHP1.3系+SQLServer2000)では
何故か実行結果が常にfalseになっちゃうのですよね。
データはちゃんと投入されているのに。
仕方ないのでその部分を自前でちまちま直して、
ついでにsave()メソッドを追加して完成\(--)/
最終的なコードはこんな感じっすφ(--)
■app/models/abs_composite_key_model.php
※2012-10-16:削除メソッド「manuallyDelete()」追加
<?php
abstract class AbsCompositeKeyModel extends AppModel {
/**
* O/Rマッパー
*
* <p>複合主キーに非対応なCakePHPのO/Rマッピングツールを使用しない。</p>
*
* @var mixed
*/
public $useTable = false;
/**
* テーブル名
*
* @var string
*/
protected $tableName = null;
/**
* テーブルのフィールド
*
* @var array
*/
protected $fieldsDefinition = array();
/**
* 複合主キー
*
* @var array
*/
protected $compositePrimaryKey = array();
/**
* Constructor.
*
* @param mixed $id Set this ID for this model on startup, can also be an array of options, see above.
* @param string $table Name of database table to use.
* @param string $ds DataSource connection name.
*/
public function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
if (empty($this->tableName)) {
trigger_error("CardRec::{$this->name} was useful table name does not exist.", E_USER_ERROR);
}
if (empty($this->fieldsDefinition)) {
trigger_error("CardRec::{$this->name} was fields definition does not exist.", E_USER_ERROR);
}
if (empty($this->compositePrimaryKey)) {
trigger_error("CardRec::{$this->name} was composite primary key does not exist.", E_USER_ERROR);
}
}
/**
* 複合主キーに対応したモデルのCREATE
*
* <p>複合キーに未対応なので、O/Rマッピングツールは使用しない。<br />
* <p>レコード追加に必要なSQLを自前で組み立てて実行する。</p>
*
* @return mixed 実行結果
*/
//public function manuallyCreate() {
public function manuallyInsert() {
$dataSource = $this->getDataSource();
$option = array();
$prepared = $this->beforeSave($option);
if (!$prepared) {
$result = false;
} else {
list($bufFields, $bufValues) = $this->buildQueryToUpdateAllItems();
$fullTableName = $dataSource->fullTableName($this->tableName);
$insertFields = implode(', ', $bufFields);
$insertValues = implode(', ', $bufValues);
$query = array('table' => $fullTableName,
'fields' => $insertFields,
'values' => $insertValues);
//$statement = $dataSource->renderStatement('create', $query);
//$dataSource->execute($statement);
//$result = $dataSource->hasResult();
$result = $dataSource->execute($dataSource->renderStatement('create', $query));
}
$this->afterSave(true);
return $result;
}
/**
* 複合主キーに対応したモデルのUPDATE
*
* <p>複合キーに未対応なので、O/Rマッピングツールは使用しない。<br />
* <p>更新に必要なSQLを自前で組み立てて実行する。</p>
*
* @return mixed 実行結果
*/
public function manuallyUpdate() {
$dataSource = $this->getDataSource();
$result = false;
if ($this->manuallyExists()) {
$option = array();
$prepared = $this->beforeSave($option);
if ($prepared) {
list($bufFields, $bufValues) = $this->buildQueryToUpdateAllItems();
$fullTableName = $dataSource->fullTableName($this->tableName);
$rawConditions = $this->builConditionsOfPrimaryKey();
$conditions = $dataSource->conditions($rawConditions, true, true, $this);
$combined = array_combine($bufFields, $bufValues);
$updates = array();
foreach ($combined as $field => $value) {
if ($value === null) {
$updates[] = "{$field} = NULL";
} else {
$updates[] = "{$field} = {$value}";
}
}
$updateFields = implode(', ', $updates);
$query = array('table' => $fullTableName,
'fields' => $updateFields,
'conditions' => $conditions);
//$statement = $dataSource->renderStatement('update', $query);
//$dataSource->execute($statement);
//$result = $dataSource->hasResult();
$result = $dataSource->execute($dataSource->renderStatement('update', $query));
}
$this->afterSave(false);
}
return $result;
}
/**
* 複合主キーに対応したモデルのEXISTS
*
* <p>複合キーに未対応なので、O/Rマッピングツールは使用しない。<br />
* <p>問い合わせに必要なSQLを自前で組み立てて実行する。</p>
*
* @return mixed 実行結果
*/
public function manuallyExists() {
$dataSource = $this->getDataSource();
$fullTableName = $dataSource->fullTableName($this->tableName);
$rawConditions = $this->builConditionsOfPrimaryKey();
$conditions = $dataSource->conditions($rawConditions, true, true, $this);
$query = array('fields' => 'COUNT(*) AS numrows',
'table' => $fullTableName,
'alias' => '',
'joins' => '',
'conditions' => $conditions,
'group' => '',
'order' => '',
'limit' => '');
$statement = $dataSource->renderStatement('select', $query);
$result = $dataSource->fetchRow($statement);
$numrows = 0;
if (isset($result[0]['numrows'])) {
$numrows = (int)$result[0]['numrows'];
}
$exists = ($numrows > 0);
return $exists;
}
/**
* 複合主キーの問い合わせ条件を組み立てる
*
* @return array 問い合わせ条件
*/
private function builConditionsOfPrimaryKey() {
foreach ($this->compositePrimaryKey as $field) {
$$field = Set::extract("{$this->alias}.{$field}", $this->data);
}
$conditions = compact($this->compositePrimaryKey);
return $conditions;
}
/**
* モデルで定義したフィールドを対象に、フィールド名と値のペアを返却
*
* @return array 更新系の命令を実行するためのデータセット
*/
private function buildQueryToUpdateAllItems() {
$dataSource = $this->getDataSource();
$bufFields = array();
$bufValues = array();
foreach ($this->fieldsDefinition as $field => $columnType) {
$bufFields[] = $field;
$rawValue = Set::extract("{$this->alias}.{$field}", $this->data);
$bufValues[] = $dataSource->value($rawValue, $columnType, false);
}
$builtQuery = array($bufFields, $bufValues);
return $builtQuery;
}
/**
* 保存 2012-10-13 add
*/
public function save($pData) {
$retValue = false; //戻り値
//値設定
$this->data = $pData;
$retValue = ($this->manuallyExists() ? $this->manuallyUpdate() : $this->manuallyInsert());
return $retValue;
}
//2012-10-16 add start
/**
* 複合主キーに対応したモデルのDELETE 2012-10-16 add
*
* <p>複合キーに未対応なので、O/Rマッピングツールは使用しない。<br />
* <p>削除に必要なSQLを自前で組み立てて実行する。</p>
*
* @return mixed 実行結果
*/
public function manuallyDelete() {
$dataSource = $this->getDataSource();
$result = false;
if ($this->manuallyExists()) {
$option = array();
$prepared = $this->beforeSave($option);
if ($prepared) {
$fullTableName = $dataSource->fullTableName($this->tableName);
$rawConditions = $this->builConditionsOfPrimaryKey();
$conditions = $dataSource->conditions($rawConditions, true, true, $this);
$query = array('table' => $fullTableName,
'alias' => "",
'conditions' => $conditions);
$result = $dataSource->execute($dataSource->renderStatement('delete', $query));
}
$this->afterSave(false);
}
return $result;
}
//2012-10-16 add end
}
?>
■app/models/hoge_model.php
<?php
require_once dirname(__FILE__) . '/abs_composite_key_model.php';
class HogeModel extends AbsCompositeKeyModel { //複合キー用のclassを継承
protected $tableName = 'table01'; //テーブル名
protected $fieldsDefinition = array( //カラム
'column01' => 'integer',
'column02' => 'string',
'column03' => 'integer',
'column04' => 'integer',
'column05' => 'string',
);
protected $compositePrimaryKey = array('column01', 'column02'); //プライマリキー(複合)
}
?>
■app/controllers/hoges_controller.php
<?php
class HogesController extends AppController {
var $name = 'Hoges';
var $uses = array(
'HogeModel',
);
public hogera() {
//値設定
$this->data['HogeModel']['column01'] = 1;
$this->data['HogeModel']['column02'] = 'a';
$this->data['HogeModel']['column03'] = 3;
$this->data['HogeModel']['column04'] = 4;
$this->data['HogeModel']['column05'] = 'b';
//保存
if($this->HogeModel->save($this->data)){
print "OK";
}else{
print "NG";
}
}
}
?>
「abs_composite_key_model.php」が複合主キーのテーブル更新用モデルで
「hoge_model.php」がテーブル用のモデル、
「hoges_controller.php」で実際にモデルを使用しています。
細かいところは頑張って解析して下さいな(^^;
そのシステムに新しい機能を追加しているのですが、
既存の別システムのテーブルを参照する必要がでてきました。
このテーブルが複合主キーのテーブルだったのです。
複合主キーのテーブルってのは、例えば「先生テーブル」ってな名前で
主キーが「学校ID」と「先生ID」みたいなテーブルね。
ん(--?
複合主キーのテーブルってCakePHPでどーやって扱うの(--?
と思ったのでえっちらおっちら調べてみたのですが、
CakePHPは複合主キーをサポートしません。
って書いてありました(--;
2.x系だったけど多分1.3系も一緒でしょ。。
……○ね!(#゚д゚)
……○にやがれ!(#゚д゚)
検索系はquery()メソッドでSQL直打ちすりゃーいーやと割り切ったけど、
更新系は流石にSQL組みたくないな~(-A-;)
だからフレームワーク嫌いなんだよ、とぶちぶち愚痴りながら調べていたら
なんか素敵なことやってる方がいらっしゃいました(人´∀`)
CakePHPで複合主キーのテーブルを更新するためのモデルを
作ってくださってる方がいらっしゃいましたよ。
こんなのφ(*´ェ`*)
CakePHPで複合主キーのテーブルを更新するためのモデル(抽象クラス)
これを参考に……と言うかほぼ丸パクリしてみたのですが、
私の環境(CakePHP1.3系+SQLServer2000)では
何故か実行結果が常にfalseになっちゃうのですよね。
データはちゃんと投入されているのに。
仕方ないのでその部分を自前でちまちま直して、
ついでにsave()メソッドを追加して完成\(--)/
最終的なコードはこんな感じっすφ(--)
■app/models/abs_composite_key_model.php
※2012-10-16:削除メソッド「manuallyDelete()」追加
<?php
abstract class AbsCompositeKeyModel extends AppModel {
/**
* O/Rマッパー
*
* <p>複合主キーに非対応なCakePHPのO/Rマッピングツールを使用しない。</p>
*
* @var mixed
*/
public $useTable = false;
/**
* テーブル名
*
* @var string
*/
protected $tableName = null;
/**
* テーブルのフィールド
*
* @var array
*/
protected $fieldsDefinition = array();
/**
* 複合主キー
*
* @var array
*/
protected $compositePrimaryKey = array();
/**
* Constructor.
*
* @param mixed $id Set this ID for this model on startup, can also be an array of options, see above.
* @param string $table Name of database table to use.
* @param string $ds DataSource connection name.
*/
public function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
if (empty($this->tableName)) {
trigger_error("CardRec::{$this->name} was useful table name does not exist.", E_USER_ERROR);
}
if (empty($this->fieldsDefinition)) {
trigger_error("CardRec::{$this->name} was fields definition does not exist.", E_USER_ERROR);
}
if (empty($this->compositePrimaryKey)) {
trigger_error("CardRec::{$this->name} was composite primary key does not exist.", E_USER_ERROR);
}
}
/**
* 複合主キーに対応したモデルのCREATE
*
* <p>複合キーに未対応なので、O/Rマッピングツールは使用しない。<br />
* <p>レコード追加に必要なSQLを自前で組み立てて実行する。</p>
*
* @return mixed 実行結果
*/
//public function manuallyCreate() {
public function manuallyInsert() {
$dataSource = $this->getDataSource();
$option = array();
$prepared = $this->beforeSave($option);
if (!$prepared) {
$result = false;
} else {
list($bufFields, $bufValues) = $this->buildQueryToUpdateAllItems();
$fullTableName = $dataSource->fullTableName($this->tableName);
$insertFields = implode(', ', $bufFields);
$insertValues = implode(', ', $bufValues);
$query = array('table' => $fullTableName,
'fields' => $insertFields,
'values' => $insertValues);
//$statement = $dataSource->renderStatement('create', $query);
//$dataSource->execute($statement);
//$result = $dataSource->hasResult();
$result = $dataSource->execute($dataSource->renderStatement('create', $query));
}
$this->afterSave(true);
return $result;
}
/**
* 複合主キーに対応したモデルのUPDATE
*
* <p>複合キーに未対応なので、O/Rマッピングツールは使用しない。<br />
* <p>更新に必要なSQLを自前で組み立てて実行する。</p>
*
* @return mixed 実行結果
*/
public function manuallyUpdate() {
$dataSource = $this->getDataSource();
$result = false;
if ($this->manuallyExists()) {
$option = array();
$prepared = $this->beforeSave($option);
if ($prepared) {
list($bufFields, $bufValues) = $this->buildQueryToUpdateAllItems();
$fullTableName = $dataSource->fullTableName($this->tableName);
$rawConditions = $this->builConditionsOfPrimaryKey();
$conditions = $dataSource->conditions($rawConditions, true, true, $this);
$combined = array_combine($bufFields, $bufValues);
$updates = array();
foreach ($combined as $field => $value) {
if ($value === null) {
$updates[] = "{$field} = NULL";
} else {
$updates[] = "{$field} = {$value}";
}
}
$updateFields = implode(', ', $updates);
$query = array('table' => $fullTableName,
'fields' => $updateFields,
'conditions' => $conditions);
//$statement = $dataSource->renderStatement('update', $query);
//$dataSource->execute($statement);
//$result = $dataSource->hasResult();
$result = $dataSource->execute($dataSource->renderStatement('update', $query));
}
$this->afterSave(false);
}
return $result;
}
/**
* 複合主キーに対応したモデルのEXISTS
*
* <p>複合キーに未対応なので、O/Rマッピングツールは使用しない。<br />
* <p>問い合わせに必要なSQLを自前で組み立てて実行する。</p>
*
* @return mixed 実行結果
*/
public function manuallyExists() {
$dataSource = $this->getDataSource();
$fullTableName = $dataSource->fullTableName($this->tableName);
$rawConditions = $this->builConditionsOfPrimaryKey();
$conditions = $dataSource->conditions($rawConditions, true, true, $this);
$query = array('fields' => 'COUNT(*) AS numrows',
'table' => $fullTableName,
'alias' => '',
'joins' => '',
'conditions' => $conditions,
'group' => '',
'order' => '',
'limit' => '');
$statement = $dataSource->renderStatement('select', $query);
$result = $dataSource->fetchRow($statement);
$numrows = 0;
if (isset($result[0]['numrows'])) {
$numrows = (int)$result[0]['numrows'];
}
$exists = ($numrows > 0);
return $exists;
}
/**
* 複合主キーの問い合わせ条件を組み立てる
*
* @return array 問い合わせ条件
*/
private function builConditionsOfPrimaryKey() {
foreach ($this->compositePrimaryKey as $field) {
$$field = Set::extract("{$this->alias}.{$field}", $this->data);
}
$conditions = compact($this->compositePrimaryKey);
return $conditions;
}
/**
* モデルで定義したフィールドを対象に、フィールド名と値のペアを返却
*
* @return array 更新系の命令を実行するためのデータセット
*/
private function buildQueryToUpdateAllItems() {
$dataSource = $this->getDataSource();
$bufFields = array();
$bufValues = array();
foreach ($this->fieldsDefinition as $field => $columnType) {
$bufFields[] = $field;
$rawValue = Set::extract("{$this->alias}.{$field}", $this->data);
$bufValues[] = $dataSource->value($rawValue, $columnType, false);
}
$builtQuery = array($bufFields, $bufValues);
return $builtQuery;
}
/**
* 保存 2012-10-13 add
*/
public function save($pData) {
$retValue = false; //戻り値
//値設定
$this->data = $pData;
$retValue = ($this->manuallyExists() ? $this->manuallyUpdate() : $this->manuallyInsert());
return $retValue;
}
//2012-10-16 add start
/**
* 複合主キーに対応したモデルのDELETE 2012-10-16 add
*
* <p>複合キーに未対応なので、O/Rマッピングツールは使用しない。<br />
* <p>削除に必要なSQLを自前で組み立てて実行する。</p>
*
* @return mixed 実行結果
*/
public function manuallyDelete() {
$dataSource = $this->getDataSource();
$result = false;
if ($this->manuallyExists()) {
$option = array();
$prepared = $this->beforeSave($option);
if ($prepared) {
$fullTableName = $dataSource->fullTableName($this->tableName);
$rawConditions = $this->builConditionsOfPrimaryKey();
$conditions = $dataSource->conditions($rawConditions, true, true, $this);
$query = array('table' => $fullTableName,
'alias' => "",
'conditions' => $conditions);
$result = $dataSource->execute($dataSource->renderStatement('delete', $query));
}
$this->afterSave(false);
}
return $result;
}
//2012-10-16 add end
}
?>
■app/models/hoge_model.php
<?php
require_once dirname(__FILE__) . '/abs_composite_key_model.php';
class HogeModel extends AbsCompositeKeyModel { //複合キー用のclassを継承
protected $tableName = 'table01'; //テーブル名
protected $fieldsDefinition = array( //カラム
'column01' => 'integer',
'column02' => 'string',
'column03' => 'integer',
'column04' => 'integer',
'column05' => 'string',
);
protected $compositePrimaryKey = array('column01', 'column02'); //プライマリキー(複合)
}
?>
■app/controllers/hoges_controller.php
<?php
class HogesController extends AppController {
var $name = 'Hoges';
var $uses = array(
'HogeModel',
);
public hogera() {
//値設定
$this->data['HogeModel']['column01'] = 1;
$this->data['HogeModel']['column02'] = 'a';
$this->data['HogeModel']['column03'] = 3;
$this->data['HogeModel']['column04'] = 4;
$this->data['HogeModel']['column05'] = 'b';
//保存
if($this->HogeModel->save($this->data)){
print "OK";
}else{
print "NG";
}
}
}
?>
「abs_composite_key_model.php」が複合主キーのテーブル更新用モデルで
「hoge_model.php」がテーブル用のモデル、
「hoges_controller.php」で実際にモデルを使用しています。
細かいところは頑張って解析して下さいな(^^;
category:CakePHP1.3系 thema:システム開発 - genre:コンピュータ Posted by ササキマコト