public function save($argments = NULL, $argReplaced = TRUE) { // insertかupdateかを決める $insert = FALSE; if (FALSE === $argReplaced) { // 強制インサート $insert = TRUE; } elseif (FALSE === $this->loaded) { // インサート $insert = TRUE; } if (is_array($argments)) { // $argmentsが配列ならargmentsの値をセット $this->sets($argments); } $replaceFields = array(); $replaceCLOBFields = array(); $replaceBLOBFields = array(); $binds = array(); if (TRUE === $insert) { // インサート処理 foreach ($this->describes as $key => $val) { if (isset($val["replace"]) && TRUE === $val["replace"]) { if ("clob" === $val["type"]) { $replaceCLOBFields[$key] = $this->{$key}; } elseif ("blob" === $val["type"]) { $replaceBLOBFields[$key] = $this->{$key}; } elseif ("date" === $val["type"]) { if ("mysql" === $this->_DBO->DBType || "postgres" === $this->_DBO->DBType) { // mysqlとPostgresはそのまま文字列を与えられる $replaceFields[$key] = " :" . $key; } elseif ("oracle" === $this->_DBO->DBType) { // Oralceでは日付型はTO_DATE関数で変換する $replaceFields[$key] = " TO_DATE(:" . $key . " , 'yyyy-mm-dd hh24:mi:ss')"; } else { // 未対応のDBエンジン throw new Exception(""); } $binds[$key] = $this->{$key}; } else { $replaceFields[$key] = " :" . $key; $binds[$key] = $this->{$key}; } } } // インサートする新しいシーケンスIDの取得に関する処理 if (NULL === $this->pkey && NULL !== $this->pkeyName && !isset($replaceFields[$this->pkeyName])) { // Insertでpkeyにあたるキーの値がセットされていなければシーケンス処理を試みる if ("mysql" === $this->_DBO->DBType) { if (isset($this->describes[$this->pkeyName]["autoincrement"]) && TRUE !== $this->describes[$this->pkeyName]["autoincrement"]) { // mysqlでも独自シーケンスを使っているのであらばそれに準拠する if (isset($sequenceSelectQuery) && NULL !== $sequenceSelectQuery && strlen($sequenceSelectQuery) > 0) { // 独自シーケンス取得SQLが定義済みならばそれを使う $seqSql = $sequenceSelectQuery; } else { // 独自シーケンス取得SQLが未定義済みならばフレームワーク固有のSQLを実行 $seqSql = "UPDATE " . strtolower($this->tableName) . "_" . $this->pkeyName . "_seq SET id=LAST_INSERT_ID(id+1)"; $response = $this->_DBO->execute($seqSql); if (FALSE === $response) { throw new Exception(""); } $seqSql = "SELECT LAST_INSERT_ID() as new_id FROM " . strtolower($this->tableName) . "_" . $this->pkeyName . "_seq"; } } else { // インサート完了後、mysqlのlast_insert_idを使う $lastInsertIdEnabled = TRUE; } } elseif ("postgres" === $this->_DBO->DBType) { // posgreは先にシーケンスを取れるので取っておく if (isset($sequenceSelectQuery) && NULL !== $sequenceSelectQuery && strlen($sequenceSelectQuery) > 0) { // 独自シーケンス取得SQLが定義済みならばそれを使う $seqSql = $sequenceSelectQuery; } else { // 独自シーケンス取得SQLが未定義済みならばフレームワーク固有のSQLを実行 $seqSql = "SELECT nextval(" . strtolower($this->tableName) . "_" . $this->pkeyName . "_seq) as new_id"; } } elseif ("oracle" === $this->_DBO->DBType) { // oracleは先にシーケンスを取れるので取っておく if (isset($sequenceSelectQuery) && NULL !== $sequenceSelectQuery && strlen($sequenceSelectQuery) > 0) { // 独自シーケンス取得SQLが定義済みならばそれを使う $seqSql = $sequenceSelectQuery; } else { // 独自シーケンス取得SQLが未定義済みならばフレームワーク固有のSQLを実行 $seqSql = "SELECT " . strtolower($this->tableName) . "_" . $this->pkeyName . "_seq.NEXTVAL as new_id FROM DUAL"; } } else { // 未対応のDBエンジン throw new Exception(""); } if (!(isset($lastInsertIdEnabled) && TRUE === $lastInsertIdEnabled)) { debug('$seqSql=' . $seqSql); $response = $this->_DBO->execute($seqSql); if (FALSE === $response) { throw new Exception(""); } else { $responseArr = $response->GetAll(); $pkey = $responseArr[0]["new_id"]; } $replaceFields[$this->pkeyName] = $pkey; debug($this->pkeyName); debug($replaceFields); } } // インサート文 $sql = "INSERT INTO `" . strtolower($this->tableName) . "` "; $sql .= "(`" . implode("`, `", array_keys($replaceFields)) . "`) "; $sql .= "VALUES (" . implode(" , ", $replaceFields) . " ) "; // DB操作実行 $response = $this->_DBO->execute($sql, $binds); if (FALSE === $response) { throw new Exception(""); } // MySQLのauto_increment用処理 if (isset($lastInsertIdEnabled) && TRUE === $lastInsertIdEnabled) { $response = $this->_DBO->execute("SELECT LAST_INSERT_ID() AS new_id FROM " . strtolower($this->tableName) . " LIMIT 1"); if (FALSE === $response) { throw new Exception(""); } else { $responseArr = $response->GetAll(); $pkey = $responseArr[0]["new_id"]; } } // CLOBを処理する $replaceCLOBFieldKeys = array_keys($replaceCLOBFields); for ($replaceCLOBFieldsNum = 0; count($replaceCLOBFields) > $replaceCLOBFieldsNum; $replaceCLOBFieldsNum++) { $key = $replaceCLOBFieldKeys[$replaceCLOBFieldsNum]; $where = "1=1"; for ($pkeyNum = 0; count($this->pkeys) > $pkeyNum; $pkeyNum++) { $where .= " AND `" . $this->pkeys[$pkeyNum] . "` = " . $this->{$this->pkeys[$pkeyNum]}; } if (FALSE === $this->_DBO->updateClob(strtolower($this->tableName), $key, $replaceCLOBFields[$key], $where)) { throw new Exception(""); } } // BLOBを処理する $replaceBLOBFieldKeys = array_keys($replaceBLOBFields); for ($replaceBLOBFieldsNum = 0; count($replaceBLOBFields) > $replaceBLOBFieldsNum; $replaceBLOBFieldsNum++) { $key = $replaceBLOBFieldKeys[$replaceBLOBFieldsNum]; $where = "1=1"; for ($pkeyNum = 0; count($this->pkeys) > $pkeyNum; $pkeyNum++) { $where .= " AND `" . $this->pkeys[$pkeyNum] . "` = " . $this->{$this->pkeys[$pkeyNum]}; } if (FALSE === $this->_DBO->updateBlob(strtolower($this->tableName), $key, $replaceBLOBFields[$key], $where)) { throw new Exception(""); } } // DB操作に成功したのでpkeyの置き換えを行う if (isset($pkey) && count($pkey) > 0) { $this->pkey = $pkey; $this->{$this->pkeyName} = $pkey; } elseif (isset($this->{$this->pkeyName}) && strlen($this->{$this->pkeyName})) { // オートインクリメント以外で、Pkeyに該当するフィールドにデータが入っていたらそれをPkeyとして自動補完する $this->pkey = $this->{$this->pkeyName}; } // XXX 読み込み済み扱いとする $this->loaded = TRUE; } else { // アップデート処理 foreach ($this->describes as $key => $val) { if (isset($val["replace"]) && TRUE === $val["replace"]) { if ("clob" === $val["type"]) { $replaceCLOBFields[$key] = $this->{$key}; } elseif ("blob" === $val["type"]) { $replaceBLOBFields[$key] = $this->{$key}; } elseif ("date" === $val["type"]) { if ("mysql" === $this->_DBO->DBType || "postgres" === $this->_DBO->DBType) { // mysqlとPostgresはそのまま文字列を与えられる $replaceFields[$key] = " `" . $key . "` = :" . $key; } elseif ("oracle" === $this->_DBO->DBType) { // oracleでは日付型はTO_DATE関数で変換する $replaceFields[$key] = " `" . $key . "` = TO_DATE( :" . $key . " , 'yyyy-mm-dd hh24:mi:ss')"; } else { // 未対応のDBエンジン throw new Exception(""); } $binds[$key] = $this->{$key}; } elseif ("int" === $val["type"] && "increment" === strtolower($this->{$key})) { $replaceFields[$key] = " `" . $key . "` = (`" . $key . "` + 1)"; } elseif ("int" === $val["type"] && "decrement" === strtolower($this->{$key})) { $replaceFields[$key] = " `" . $key . "` = (`" . $key . "` - 1)"; } else { $replaceFields[$key] = " `" . $key . "` = :" . $key; $binds[$key] = $this->{$key}; } } } // アップデート文 $sql = "UPDATE `" . strtolower($this->tableName) . "` "; $sql .= "SET " . implode(" , ", $replaceFields) . " "; $sql .= "WHERE 1=1 "; if (NULL !== $this->pkeys && TRUE === is_array($this->pkeys) && count($this->pkeys) > 1) { // 複合プライマリーキーの為の処理 foreach ($this->pkeys as $key => $val) { $sql .= "AND `" . $val . "` = :pkey_" . $val . " "; $binds["pkey_" . $val] = $this->{$val}; } } elseif (NULL !== $this->pkeyName) { // 単一プライマリーキーの処理 $sql .= "AND `" . $this->pkeyName . "` = :pkey_" . $this->pkeyName . " "; $binds["pkey_" . $this->pkeyName] = $this->pkey; } else { // プライマリーキーが無いレコードなので foreach ($replaceFields as $key => $val) { $sql .= "AND `" . $key . "` = :before_" . $key . " "; $binds["before_" . $key] = $this->describes[$key]["before"]; } } // DB操作実行 $response = $this->_DBO->execute($sql, $binds); if (FALSE === $response) { throw new Exception(""); } // CLOBを処理する $replaceCLOBFieldKeys = array_keys($replaceCLOBFields); for ($replaceCLOBFieldsNum = 0; count($replaceCLOBFields) > $replaceCLOBFieldsNum; $replaceCLOBFieldsNum++) { $key = $replaceCLOBFieldKeys[$replaceCLOBFieldsNum]; $where = "1=1"; for ($pkeyNum = 0; count($this->pkeys) > $pkeyNum; $pkeyNum++) { $where .= " AND `" . $this->pkeys[$pkeyNum] . "` = " . $this->{$this->pkeys[$pkeyNum]}; } if (FALSE === $this->_DBO->updateClob(strtolower($this->tableName), $key, $replaceCLOBFields[$key], $where)) { throw new Exception(""); } } // BLOBを処理する $replaceBLOBFieldKeys = array_keys($replaceBLOBFields); for ($replaceBLOBFieldsNum = 0; count($replaceBLOBFields) > $replaceBLOBFieldsNum; $replaceBLOBFieldsNum++) { $key = $replaceBLOBFieldKeys[$replaceBLOBFieldsNum]; $where = "1=1"; for ($pkeyNum = 0; count($this->pkeys) > $pkeyNum; $pkeyNum++) { $where .= " AND `" . $this->pkeys[$pkeyNum] . "` = " . $this->{$this->pkeys[$pkeyNum]}; } if (FALSE === $this->_DBO->updateBlob(strtolower($this->tableName), $key, $replaceBLOBFields[$key], $where)) { throw new Exception(""); } } // DB操作に成功したのでpkeyの置き換えを行う(Updateで置き換わってる場合があるので) $this->pkey = $this->{$this->pkeyName}; } // DB操作に成功したのでdescribes内のreplaceとexec値を初期化しておく foreach ($replaceFields as $key => $val) { if ("int" === $this->describes[$key]["type"] && 'increment' === $this->{$key}) { $this->{$key} = (int) $this->describes[$key]["before"] + 1; } elseif ("int" === $this->describes[$key]["type"] && 'decrement' === $this->{$key}) { $this->{$key} = (int) $this->describes[$key]["before"] - 1; } $this->describes[$key]["replace"] = NULL; } return TRUE; }