XOOPS用汎用TebleObject
XOOPSでは、モジュールでのDBのハンドリングのために、XoopsObjectとXoopsObjectHandlerというひな形となるクラスが用意されているけど、結局はXoopsObjectHandlerの派生クラスにてSQL文を生成するロジックを書いてやらないといけない。
ということで、試しに汎用的なTable操作を可能にしたXoopsTableObject及びXoopsTableObjectHandlerクラスというのを試作してテーブルによる、アクセスを簡便化してみた。
これを使うと、たとえば id,name,telnumという項目を持つ、modsample0_table1というテーブルに対して、
<?php
include_once XOOPS_ROOT_PATH."/util/xoopstableobject.php";
/**
* サンプルテーブルオブジェクト
*
* @copyright copyright (c) 2000-2003 Kowa.ORG
* @author Nobuki Kowa <[email protected]>
* @package ModSample0l
*/
class ModSample0Table1 extends XoopsTableObject
{
/**
* コンストラクタ
*/
function ModSample0Table1()
{
////////////////////////////////////////
// 各クラス共通部分(書換不要)
////////////////////////////////////////
//親クラスのコンストラクタ呼出
$this->XoopsTableObject();
////////////////////////////////////////
// 派生クラス固有の定義部分
////////////////////////////////////////
//各オブジェクト要素の定義
$this->initVar('id', XOBJ_DTYPE_INT, NULL, false);
$this->initVar('name', XOBJ_DTYPE_TXTBOX, NULL, true, 20);
$this->initVar('telnum', XOBJ_DTYPE_TXTBOX, NULL, false,13);
//プライマリーキーの定義
$this->setKeyFields(array('id'));
//AUTO_INCREMENT属性のフィールド定義
// - 一つのテーブル内には、AUTO_INCREMENT属性を持つフィールドは
// 一つしかない前提です。
$this->setAutoIncrementField('id');
$this->assignEditFormElement('id','Hidden', array('id',0));
$this->assignEditFormElement('name','Text',array('名前','name',20,20));
$this->assignEditFormElement('telnum','Text',array('電話番号','telnum',15,13));
$this->assignListTableElement('name','Link','名前');
$this->assignListTableElement('telnum','Text','電話番号');
}
}
/**
* サンプルテーブルハンドラオブジェクト
*
* @copyright copyright (c) 2000-2003 Kowa.ORG
* @author Nobuki Kowa <[email protected]>
* @package ModSample0l
*/
class ModSample0Table1Handler extends XoopsTableObjectHandler
{
/**
* コンストラクタ
*/
function ModSample0Table1Handler($db)
{
////////////////////////////////////////
// 各クラス共通部分(書換不要)
////////////////////////////////////////
//親クラスのコンストラクタ呼出
$this->XoopsTableObjectHandler($db);
////////////////////////////////////////
// 派生クラス固有の定義部分
////////////////////////////////////////
//ハンドラの対象テーブル名定義
$this->tableName = $this->db->prefix('modsample0_table1');
//関連クラス名称を小文字で定義
// - 標準のネーミングに準拠している場合には設定不要
// $this->objectClassName = 'modsample0table1';
}
/**
* レコードの取得(プライマリーキーによる一意検索)
*
* @param string $key 検索キー
*
* @return object {@link ModSample0Table1}, FALSE on fail
*/
/*テーブルに固有の処理が必要な時以外は不要
function &get($key)
{
return parent::get($key);
}
*/
/**
* レコードの保存
*
* @param object &$record {@link ModSample0Table1} object
* @param bool $force POSTメソッド以外で強制更新する場合はture
*
* @return bool 成功の時は TRUE
*/
/*テーブルに固有のデータ処理が必要な時以外は不要
function insert(&$record,$force=false)
{
return parent::insert($record,$force);
}
*/
/**
* レコードの削除
*
* @param object &$record {@link ModSample0Table1} object
* @param bool $force POSTメソッド以外で強制更新する場合はture
*
* @return bool 成功の時は TRUE
*/
/*テーブルに固有のデータ処理が必要な時以外は不要
function delete(&$record,$force=false)
{
return parent::delete($record,$force);
}
*/
/**
* テーブルの条件検索による複数レコード取得
*
* @param object $criteria {@link CriteriaElement} 検索条件
* @param bool $id_as_key プライマリーキーを、戻り配列のキーにする場合はtrue
* @return mixed Array 検索結果レコードの配列
*/
/*テーブルに固有のデータ処理が必要な時以外は不要
function &getObjects($criteria = null, $id_as_key = false)
{
return parent::getObjects($criteria, $id_as_key);
}
*/
}
?>
というコードを書くだけで、基本的なDBアクセスが可能になって、
このクラスを使って、たとえば、モジュールのindex.phpに
<?PHP
global $xoopsDB;
// XOOPSの環境設定ファイルの読込
require( '../../mainfile.php' ) ;
// 使用するSmartyテンプレートの宣言
// XOOPSの共通ヘッダー部分の描画
include( XOOPS_ROOT_PATH.'/header.php' ) ;
include_once XOOPS_ROOT_PATH.'/modules/ModSample0/class/ModSample0_Table1.php';
//実際のデータ処理を記述します。
$handler = new ModSample0Table1Handler($xoopsDB);
$op = array_key_exists('op',$_POST) ? $_POST['op'] : ( array_key_exists('op',$_GET) ? $_GET['op'] :'');
switch ($op) {
case 'insert':
$record =& $handler->create();
$record->setFormVars($_POST,'');
$handler->insert($record,true);
redirect_header("",1,$title);
exit();
break;
case 'save':
$record =& $handler->create();
$record->setFormVars($_POST,'');
$record->unsetNew();
$handler->insert($record,true);
redirect_header("",1,$title);
exit();
break;
case 'edit':
$xoopsOption['template_main']= 'ModSample0_main.html';
$record =& $handler->get($_GET);
$body = $record->renderEditForm("登録","edit",XOOPS_URL."/modules/ModSample0/index.php");
$xoopsTpl->assign('body', $body);
break;
default :
$xoopsOption['template_main']= 'ModSample0_list.html';
$new_record =& $handler->create();
$insertform = $new_record->renderEditForm("新規登録","insert",XOOPS_URL."/modules/ModSample0/index.php");
$criteria = new CriteriaElement();
$criteria->setSort('name');
$criteria->setStart(1);
$criteria->setLimit(10);
$recordobjs =& $handler->getObjects($criteria);
foreach ($recordobjs as $record) {
foreach($record->getvars() as $k=>$v) {
$rec[$k]=$record->getVar($k);
}
$records[] = $rec;
}
$xoopsTpl->assign('insertform', $insertform);
$xoopsTpl->assign('lang_list_title','一覧');
$xoopsTpl->assign('lang_name','氏名');
$xoopsTpl->assign('lang_telnum','電話番号');
$xoopsTpl->assign('records', $records);
}
// XOOPSの共通フッター部分の描画
include( XOOPS_ROOT_PATH.'/footer.php' ) ;
?>
と定義する事によって、レコードの新規登録、一覧表示、編集機能を実現できるようになる。
とりあえず現状出来ている暫定的な、XoopsTableObject クラスは以下のようなものである。
<?php
include_once XOOPS_ROOT_PATH."/class/xoopsobject.php";
/**
* 汎用テーブル操作XoopsObject
*
* @copyright copyright (c) 2000-2003 Kowa.ORG
* @author Nobuki Kowa <[email protected]>
* @package ModSample0l
*/
class XoopsTableObject extends XoopsObject
{
var $_keys;
var $_autoIncrement;
var $_formElements;
var $_listTableElements;
function XoopsTableObject()
{
//親クラスのコンストラクタ呼出
$this->XoopsObject();
}
function setKeyFields($keys)
{
$this->_keys = $keys;
}
function getKeyFields()
{
return $this->_keys;
}
function isKey($field)
{
return in_array($field,$this->_keys);
}
//AUTO_INCREMENT属性のフィールドはテーブルに一つしかない前提
function setAutoIncrementField($fieldName)
{
$this->_autoIncrement = $fieldName;
}
function &getAutoIncrementField()
{
return $this->_autoIncrement;
}
function isAutoIncrement($fieldName)
{
return ($fieldName == $this->_autoIncrement);
}
function resetChenged()
{
foreach($this->vars as $k=>$v) {
$this->vars[$k]['changed'] = false;
}
}
function assignEditFormElement($name,$class,$params)
{
include_once XOOPS_ROOT_PATH.'/class/xoopsform/formelement.php';
include_once XOOPS_ROOT_PATH.'/class/xoopsform/form'. strtolower($class) .'.php';
$className = "XoopsForm". $class;
$callstr = '$this->_formElements["'.$name.'"] = new XoopsForm'.$class.'(';
$delim = '';
for ($i=0;$i<count($params);$i++) {
if (gettype($params[$i]) == "string") {
$callstr .= $delim. '"'. $params[$i].'"';
} else {
$callstr .= $delim. $params[$i];
}
$delim = ', ';
}
$callstr .= ');';
// echo "$callstr<br>";
eval($callstr);
}
function renderEditForm($caption,$name,$action)
{
include_once XOOPS_ROOT_PATH.'/class/xoopsform/form.php';
include_once XOOPS_ROOT_PATH.'/class/xoopsform/themeform.php';
include_once XOOPS_ROOT_PATH.'/class/xoopsform/formhidden.php';
include_once XOOPS_ROOT_PATH.'/class/xoopsform/formbutton.php';
$formEdit =& new XoopsThemeForm($caption,$name,$action);
foreach ($this->_formElements as $key=>$formElement) {
if (!$this->isNew()) {
$formElement->setValue($this->getVar($key));
}
$formEdit->addElement(&$formElement,$this->vars[$key]['required']);
// echo "$key - " .get_class($formElement) ."<br/>";
unset($formElement);
}
if ($this->isNew()) {
$formEdit->addElement(new XoopsFormHidden('op','insert'));
} else {
$formEdit->addElement(new XoopsFormHidden('op','save'));
}
$formEdit->addElement(new XoopsFormButton('', 'submit', 'OK', 'submit'));
$str = $formEdit->render();
unset($formEdit);
return $str;
}
function assignListTableElement($name,$type, $caption) {
$_listTableElements[$name]['type'] = $type;
$_listTableElements[$name]['caption'] = $caption;
}
}
class XoopsTableObjectHandler extends XoopsObjectHandler
{
var $tableName;
var $entityClassName;
var $keyClassName;
function XoopsTableObjectHandler($db)
{
$this->entityClassName = preg_replace("/handler/","", get_class($this));
$this->keyClassName = $this->entityClassName .'key';
$this->XoopsObjectHandler($db);
}
function &create($isNew = true)
{
$perm = new $this->entityClassName;
if ($isNew) {
$perm->setNew();
}
return $perm;
}
/**
* レコードの取得(プライマリーキーによる一意検索)
*
* @param mixed $key 検索キー
*
* @return object {@link XoopsTableObject}, FALSE on fail
*/
function &get($keys)
{
$record = new $this->entityClassName;
$recordKeys = $record->getKeyFields();
$recordVars = $record->getVars();
if (gettype($keys) != 'array') {
if (count($recordKeys) == 1) {
$keys = array($recordKeys[0] => $keys);
}
}
$whereStr = "";
$whereAnd = "";
foreach ($record->getKeyFields() as $k => $v) {
if (array_key_exists($v, $keys)) {
$whereStr = $whereAnd . "`$v` = ";
if ($recordVars[$v]['data_type'] == XOBJ_DTYPE_INT) {
$whereStr .= $keys[$v];
} else {
$whereStr .= $this->db->quoteString($keys[$v]);
}
$whereAnd = " AND ";
} else {
return false;
}
}
$sql = sprintf("SELECT * FROM %s WHERE %s",$this->tableName, $whereStr);
// echo $sql."<br/>";
if ( !$result = $this->db->query($sql) ) {
return false;
}
$numrows = $this->db->getRowsNum($result);
if ( $numrows == 1 ) {
$record->assignVars($this->db->fetchArray($result));
return $record;
}
unset($record);
return false;
}
/**
* Store a {@link XoopsTableObject}
*
* @param object &$record {@link XoopsTableObject} object
*
* @return bool TRUE on success
*/
function insert(&$record,$force=false,$updateOnlyChanged=false)
{
if ( get_class($record) != $this->entityClassName ) {
return false;
}
if ( !$record->isDirty() ) {
return true;
}
if (!$record->cleanVars()) {
return false;
}
$vars = $record->getVars();
if ($record->isNew()) {
$fieldList = "(";
$valueList = "(";
$delim = "";
foreach ($record->cleanVars as $k => $v) {
$fieldList .= $delim ."`$k`";
if ($record->isAutoIncrement($k)) {
$v = $this->getAutoIncrementValue();
}
if ($vars[$k]['data_type'] == XOBJ_DTYPE_INT) {
$valueList .= $delim . $v;
} else {
$valueList .= $delim . $this->db->quoteString($v);
}
$delim = ", ";
}
$fieldList .= ")";
$valueList .= ")";
$sql = sprintf("INSERT INTO %s %s VALUES %s", $this->tableName,$fieldList,$valueList);
} else {
$setList = "";
$setDelim = "";
$whereList = "";
$whereDelim = "";
foreach ($record->cleanVars as $k => $v) {
if ($vars[$k]['data_type'] == XOBJ_DTYPE_INT) {
$value = $v;
} else {
$value = $this->db->quoteString($v);
}
if ($record->isKey($k)) {
$whereList .= $whereDelim . "`$k` = ". $value;
$whereDelim = " AND ";
} else {
if ($updateOnlyChanged && !$vars[$k]['changed']) {
continue;
}
$setList .= $setDelim . "`$k` = ". $value . " ";
$setDelim = ", ";
}
}
$sql = sprintf("UPDATE %s SET %s WHERE %s", $this->tableName, $setList, $whereList);
}
// echo $sql."<br/>";
if ($force) {
if (!$result = $this->db->queryF($sql)) {
return false;
}
} else {
if (!$result = $this->db->query($sql)) {
return false;
}
}
$idField=$record->getAutoIncrementField();
if (empty($$idField)) {
$$idField = $this->db->getInsertId();
}
$record->assignVar($idField,$$idField);
$record->resetChenged();
return true;
}
/**
* Delete a {@link ModSample0Table1}
*
* @param object &$modsample0table1
*
* @return bool TRUE on success
*/
function delete(&$record,$force=false)
{
if ( get_class($record) != $this->entityClassName ) {
return false;
}
$vars = $record->getVars();
$whereList = "";
$whereDelim = "";
foreach ($record->cleanVars as $k => $v) {
if ($record->isKey($k)) {
if ($vars[$k]['data_type'] == XOBJ_DTYPE_INT) {
$value = $v;
} else {
$value = $this->db->quoteString($v);
}
$whereList .= $whereDelim . "`$k` = ". $value;
$whereDelim = " AND ";
}
}
$sql = sprintf("DELETE FROM %s WHERE %s", $this->tableName, $whereList);
if ($force) {
if (!$result = $this->db->queryF($sql)) {
return false;
}
} else {
if (!$result = $this->db->query($sql)) {
return false;
}
}
return true;
}
/**
* retrieve groups from the database
*
* @param object $criteria {@link CriteriaElement} with conditions for the groups
* @param bool $id_as_key should the groups' IDs be used as keys for the associative array?
* @return mixed Array of groups
*/
function &getObjects($criteria = null, $id_as_key = false)
{
$ret = array();
$limit = $start = 0;
$sql = 'SELECT * FROM '.$this->tableName;
if (isset($criteria) && is_subclass_of($criteria, 'criteriaelement')) {
$sql .= ' '.$criteria->renderWhere();
}
if (isset($criteria) && (is_subclass_of($criteria, 'criteriaelement')||get_class($criteria)=='criteriaelement')) {
if ($criteria->getSort() != '') {
$sql .= ' ORDER BY '.$criteria->getSort().' '.$criteria->getOrder();
}
$limit = $criteria->getLimit();
$start = $criteria->getStart();
}
// echo $sql."<br />";
$result = $this->db->query($sql, $limit, $start);
if (!$result) {
return $ret;
}
while ($myrow = $this->db->fetchArray($result)) {
$record = new $this->entityClassName;
$record->assignVars($myrow);
if (!$id_as_key) {
$records[] =& $record;
} else {
$id =$record->getIdKeyField();
if ($id) {
$records[$myrow[$id]] =& $record;
}
}
unset($record);
}
return $records;
}
function getAutoIncrementValue()
{
return $this->db->genId(get_class($this).'_id_seq');
}
}
?>
なんかのヒントになるかなぁ?
コメント
- 参考の為にModSample0を添付しておきます。 -- nobunobu
- 先日メールで問い合わさせて頂いたものです。試験モジュールでも見れるようにして頂いてありがとうございます。構造がようやく飲み込めてきました。ありがとうございました。 -- taraki