返信する: ぶろぐコメント
対象モジュール | なーお'nぶろぐ |
件名 | [xoops] フォーラムモジュ-ル「xcforum」製作開始 |
要旨 | d3forumの後継フォーラム・掲示板モジュール、「xcforum」を作り始めました。 自分にはかなーりハードルが高いのですが、 facebookのグループで色々相談しながらできそうなんで、もしかしたらできるかも。 facebook内の当該スレ それに、「factory」という、モジュール自動生成サイトがるのでこれを利用します。 で、今後の参考になるかもしれないので、できるだけメモを残しておきます。 ... |
- Re: [xoops] フォーラムモジュ-ル「xcforum」製作開始
- 投稿者: なーお 投稿日時: 2012/3/7 12:04
[xcforum開発] 徐々に進んでます。
壁にぶつかっていたのは、TopicsList表示で 複数テーブルをJOINして複数の検索条件を付加する部分。 JOINせずにロジックを回していたんだけど、長くなるし見通しも悪いコードになりそうな悪寒。。
複数テーブルをJOINすること自体、XoopsObject・criteriaではできない。 そこでfacebook上でヒントをいただき、d3forumの元のSQLで抽出し、 表示だけをfactoryが生成するobjetに放り込む方法を取ることで、解決。 ユーザーがチェック済みの投稿のアイコンを変える部分なども問題無くクリアできた。
ところで、d3forumはフォーラム内に独自の検索があって、このクエリ文字をfactoryで作られたPageNaviに反映する方法が今一つ判らない。今のままだと、実際のクエリ結果とPageNaviの表示がバラバラ。 テンプレート内にはsmartyプラグインが書かれていて、プラグインからpageNaviのオブジェクト内メソッドをあれこれ呼んで作っているので、まあその辺を解析して割り込めれば何とかなると思うんだけど・・
最終的には見た目もBoxNavi的にしたいし、これはd3forumで組み込んだクラスをやっぱり使うのがいいかな。
他方のソート機能はテンプレートにクエリ文字分を付加するだけでOKだったから、そちらは有り難く使わせていただきます!以下、今回の実装に関連するソースコード部分。
ハンドラクラス
Legacy_AbstractClientObjectHandler を継承したクラス内に、最低限、以下の2つのメソッドを実装。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
public function &getObjects($criteria = null, $limit = null, $start = null, $id_as_key = false, $custom_sql = null, $add_init = 0 ) { $ret = array(); if ( !$custom_sql ){ return parent::getObjects($criteria, $limit, $start, $id_as_key); } else { $sql = $custom_sql; if ($limit === null) { $limit = $criteria->getLimit(); } if ($start === null) { $start = $criteria->getStart(); } $sorts = array(); foreach ($criteria->getSorts() as $sort) { $sorts[] = '`' . $sort['sort'] . '` ' . $sort['order']; } if ($criteria->getSort() != '') { $sql .= " ORDER BY " . implode(',', $sorts); } $result = $this->db->query($sql, $limit, $start); if (!$result) { return $ret; } while($row = $this->db->fetchArray($result)) { $obj =new $this->mClass(); if ($add_init>=1){ // added $obj->initAdditionalFields( $add_init ); } $obj->mDirname = $this->getDirname(); $obj->assignVars($row); $obj->unsetNew(); if ($id_as_key) { $ret[$obj->get($this->mPrimary)] =& $obj; } else { $ret[]=&$obj; } unset($obj); } return $ret; } } function getCount($criteria = null, $custom_sql = null ) { if ( !$custom_sql ){ return parent::getCount($criteria); } else { $sql = "SELECT COUNT(*) c ".$custom_sql; return $this->_getCount($sql); } }
オブジェクトクラス
Xcforum_TopicsObject 内に、オブジェクト内メンバ変数を後処理で初期化するメソッドを追加して、topicsテーブル内にJOINしたテーブルデータや他の諸々のデータも、Object内に格納できるようにする。 呼び元は上記getObject()中にあり。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
public function initAdditionalFields( /*** int ***/ $init_mode = 0 ) { // additional items $this->initVar('lp_post_text', XOBJ_DTYPE_TEXT, '', false); $this->initVar('lp_subject', XOBJ_DTYPE_STRING, '', false, 255); $this->initVar('lp_icon', XOBJ_DTYPE_INT, '', false); $this->initVar('lp_number_entity', XOBJ_DTYPE_INT, '', false); $this->initVar('lp_special_entity', XOBJ_DTYPE_INT, '', false); $this->initVar('lp_guest_name', XOBJ_DTYPE_STRING, '', false, 25); $this->initVar('fp_post_text', XOBJ_DTYPE_TEXT, '', false); $this->initVar('fp_subject', XOBJ_DTYPE_STRING, '', false, 255); $this->initVar('fp_icon', XOBJ_DTYPE_INT, '', false); $this->initVar('fp_number_entity', XOBJ_DTYPE_INT, '', false); $this->initVar('fp_special_entity', XOBJ_DTYPE_INT, '', false); $this->initVar('fp_guest_name', XOBJ_DTYPE_STRING, '', false, 25); $this->initVar('u2t_time', XOBJ_DTYPE_INT, '', false); $this->initVar('u2t_marked', XOBJ_DTYPE_INT, '', false); $this->initVar('u2t_rsv', XOBJ_DTYPE_INT, '', false); if ($init_mode >= 2){ $this->initVar('forum_title', XOBJ_DTYPE_STRING, '', 255); } }
SQLとgetObjects
そして、肝心のObject取得部分は、以下の感じ。 現時点ではコントローラに書いちゃっているけど、もう少し粒度を細かくして、共通クラスに放り込んでブロックからも使えるようにできるといいかなあ。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
public function getDefaultView() { $handler = Legacy_Utils::getModuleHandler('forums', $this->mAsset->mDirname); if ( isset($this->forum_id) && $this->forum_id > 0 ){ $this->mForumObj = $handler->get($this->forum_id); } else { $this->mForumObj = $handler->create(); } // set moderators $handler->setModerateGroups( $this->mForumObj, $this->forum_id ); $handler->setModerateUsers( $this->mForumObj, $this->forum_id ); $this->mFilter =& $this->_getFilterForm(); $this->mFilter->fetch(); $handler =& $this->_getHandler(); $mCriteria = $this->mFilter->getCriteria(); $mCriteria->add(new criteria('forum_id', $this->mForumAcc['can_read'], 'IN')); $db = $this->mRoot->mController->mDB; $dirname = $this->mAsset->mDirname; $uid = $this->mRoot->mContext->mUser->isInRole('Site.RegisteredUser') ? $this->mRoot->mContext->mXoopsUser->get('uid') : 0 ; // forum_id if ( $this->forum_id > 0 ){ $whr_forum = 't.forum_id=' . $this->forum_id; $isadminormod = $this->mod_isadmin ? true : in_array( $this->forum_id, $this->mForumAcc['moderate']); $fields_forum = ""; $join_forum = ""; $initial_mode = 1; } else { $whr_forum = 't.forum_id IN (' . implode(',', $this->mForumAcc['can_read']) . ') '; $isadminormod = $this->mod_isadmin ? true : false ; $fields_forum = ", f.forum_id, f.forum_title, f.forum_external_link_format "; $join_forum = " LEFT JOIN ".$db->prefix($dirname."_forums")." f ON f.forum_id=t.forum_id "; $initial_mode = 2; } // INVISIBLE $whr_invisible = $isadminormod ? '1' : '! t.topic_invisible' ; // SOLVED $this->solved_options = array( 0 => '----' , 1 => _MD_XCFORUM_OPT_SOLVEDYES , 2 => _MD_XCFORUM_OPT_SOLVEDNO , ) ; $solved_sqls = array( 0 => '1' , 1 => 't.topic_solved=1' , 2 => 't.topic_solved=0' , ) ; if( empty( $this->mod_config['use_solved' ] ) ) { // disable "solved function" $query4assign['solved'] = 0 ; $whr_solved = $solved_sqls[0] ; } else { $q_solved = (int)$this->mRoot->mContext->mRequest->getRequest('solved'); if( ! empty( $this->solved_options[$q_solved] ) ) { $query4assign['solved'] = $q_solved ; $whr_solved = $solved_sqls[ $query4assign['solved'] ] ; } else { $query4assign['solved'] = 0 ; $whr_solved = $solved_sqls[0] ; } } // TXT $myts =& Xcforum_Utils::getMytextSanitizer(); $q_txt = $this->mRoot->mContext->mRequest->getRequest('txt'); //adump($this->mRoot->mContext->mRequest->getRequest('txt')); //$q_txt = $_GET['txt']; if( ! empty( $q_txt ) ) { $txt = $myts->stripSlashesGPC( $q_txt ) ; $query4assign['txt'] = htmlspecialchars( $txt , ENT_QUOTES , _CHARSET ) ; $txt4sql = addslashes( $txt ) ; $whr_txt = "fp.subject LIKE '%$txt4sql%' OR fp.post_text LIKE '%$txt4sql%'" ; } else { $query4assign['txt'] = '' ; $whr_txt = '1' ; } $this->query4assign = $query4assign; $limit = $this->mod_config['topics_per_page']; // get counts of total topics $sql_base = "FROM " .$db->prefix($dirname."_topics")." t LEFT JOIN " .$db->prefix($dirname."_users2topics")." u2t ON t.topic_id=u2t.topic_id AND u2t.uid=$uid LEFT JOIN " .$db->prefix($dirname."_posts")." lp ON lp.post_id=t.topic_last_post_id LEFT JOIN " .$db->prefix($dirname."_posts")." fp ON fp.post_id=t.topic_first_post_id ".$join_forum." WHERE ($whr_forum) AND ($whr_invisible) AND ($whr_solved) AND ($whr_txt)" ; $sql = $sql_base; $this->topic_hits = $handler->getCount( $mCriteria, $sql ); // get topic objects $sql = "SELECT t.*, lp.post_text AS lp_post_text, lp.subject AS lp_subject, lp.icon AS lp_icon, lp.number_entity AS lp_number_entity, lp.special_entity AS lp_special_entity, lp.guest_name AS lp_guest_name, fp.subject AS fp_subject, fp.icon AS fp_icon, fp.number_entity AS fp_number_entity, fp.special_entity AS fp_special_entity, fp.guest_name AS fp_guest_name, u2t.u2t_time, u2t.u2t_marked, u2t.u2t_rsv ".$fields_forum.$sql_base; // No6 argument is for additional initializztion : 1::forum_id>0, 2::forum_id==0 $this->mObjects =& $handler->getObjects( $mCriteria, NULL, NULL, false, $sql, $initial_mode ); return XCFORUM_FRAME_VIEW_INDEX; }