T4-データベースを使う

ブロックタイプのプラグインは、Maharaデータベース中に独自のテーブルを持つことができる。例えば、今回の SimpleClock に、「あなたが前回このページを訪れたのは YYYY年MM月DD日です」などという表示をしたいと考えよう。そのためには、このブロックが表示されるたびに

  1. 閲覧しているユーザを取得
  2. 現在時刻を取得
  3. ユーザIDと現在時刻を記録する

という処理をして記録しておく必要がある。表示する際には、この記録処理の前に前回の記録を読み込んできてやればよい。

テーブルの作成

この目的のために,Maharaデータベースに以下のようなフィールドを持つテーブルを作成する。

Table "blocktype_simpleclock_visit"

ColumnType
blockinstancebigint
userbigint
lastvisittimestamp
countvistint

blockinstanceは、ページに配置されたブロックモジュールを表す識別番号で、block_instance.id (テーブル block_instance の、フィールド id) を外部キーとして参照する。userは閲覧者を表す識別番号で、usr.idを外部キーとして参照する。このテーブルの主キーは(blockinstance,user)となる。

lastvisitとcountvisitがわれわれのブロックプラグインの独自データで、それぞれ直近のアクセス日時、累計のアクセス回数を示す。

このようなテーブルをどうやって作るのだろうか。データベースに直接アクセスして手動で作る、という必要はない。管理者がブロック型プラグインを「表示」するタイミングで、特定のファイル(db/install.xml)の内容に従ってMaharaが作成してくれる。install.xml の内容はXMLDBに従って作成する。

db/install.xml

<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="lib/db" VERSION="20060926" COMMENT="XMLDB file for core Mahara tables"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
    <TABLES>
        <TABLE NAME="blocktype_simpleclock_visit">
            <FIELDS>
                <FIELD NAME="blockinstance" TYPE="int" LENGTH="8" NOTNULL="true" />
                <FIELD NAME="usr"           TYPE="int" LENGTH="8" NOTNULL="true" />
                <FIELD NAME="lastvisit"     TYPE="datetime" NOTNULL="true" />
                <FIELD NAME="countvisit"    TYPE="int" LENGTH="4" NOTNULL="true" />
            </FIELDS>
            <KEYS>
                <KEY NAME="primary" TYPE="primary" FIELDS="blockinstance,usr" />
                <KEY NAME="instancefk" TYPE="foreign" FIELDS="blockinstance" REFTABLE="block_instance" REFFIELDS="id" />
                <KEY NAME="usrfk" TYPE="foreign" FIELDS="usr" REFTABLE="usr" REFFIELDS="id" />
            </KEYS>
        </TABLE>
    </TABLES>
</XMLDB>

現在、われわれのブロックプラグインのファイル構成は下記のようになっている。

simpleclock/
 +-- version.php
 +-- lib.php
 +-- lang/
 |    +-- en.utf8/
 |    |     +-- blocktype.simpleclock.php
 |    +-- ja.utf8/
 |          +-- blocktype.simpleclock.php
 +-- db/
      +-- install.xml

T2 の要領に従って一旦プラグインを削除し、もう一度管理者でインストールすると、以下のようなテーブルができているはずだ。

(postgresql の psql での表示)
maharadb=> \d blocktype_simpleclock_visit 
       Table "public.blocktype_simpleclock_visit"
    Column     |            Type             | Modifiers 
---------------+-----------------------------+-----------
 blockinstance | integer                     | not null
 usr           | integer                     | not null
 lastvisit     | timestamp without time zone | not null
 countvisit    | smallint                    | not null
Indexes:
    "blocsimpvisi_blousr_pk" PRIMARY KEY, btree (blockinstance, usr)
    "blocsimpvisi_blo_ix" btree (blockinstance)
    "blocsimpvisi_usr_ix" btree (usr)
Foreign-key constraints:
    "blocsimpvisi_blo_fk" FOREIGN KEY (blockinstance) REFERENCES block_instance(id)
    "blocsimpvisi_usr_fk" FOREIGN KEY (usr) REFERENCES usr(id)

ページ情報などの取得

データベーステーブルへのアクセスの前に、「アクセスしているのは誰なのか?」「このページはどのページなのか?」といったMahara的な情報を取得する必要がある。

BlockInstance ID

render_instance には、BlockInstance のオブジェクトが第一引数として渡されてくる。この場合、これが自分自身を表すオブジェクトとなっているはずである。そのIDは下記のようにして得られる。

$blockinstance_id = $instance->get('id');

View ID

自分自身がおかれている View(ページ)のID。

$view_id = $instance->get_view()->get('id');

Owner ID

上記Viewの所有者のID。

$owner = $instance->get_view()->get('owner');

User ID

アクセスしているユーザは、グローバル変数 $USER から取得できる。

global $USER;
$userid = (!empty($USER) ? $USER->get('id') : -1);

テーブルへのアクセス

MaharaではMoodleで開発されたXMLDB関数を使ってテーブルへアクセスする。XMLDBのドキュメントはこのへんだが、ちょっと使い方が違うようだ。Maharaのソースを見た方が確実で早いと思う。Maharaに入ってるXMLDB関数のソースは lib/dml.php で、作者表示は Martin Dougiamas となっている。dml.phpで定義されている、データベースへアクセスするために使える関数の一覧はこちら参照。

とりあえず、一行を select する get_record と、upsert する ensure_record_exists を使って、訪問日の表示と保存をするように書き換えてみた lib.php は以下のようになる。render_instance() の定義部分だけ抜き出している。

lib.php

    public static function render_instance(BlockInstance $instance, $editing=false) {
        $bid = $instance->get('id');
        global $USER;
        $uid = (!empty($USER) ? $USER->get('id') : 0);

        // while editing page, we do not want to record page access.
        if ( $editing) {
            return "(editing page)";
        }

        $now = db_format_timestamp(time());


        // Get one record from out table 'blocktype_simpleclock_visit'
        // 
        // this is equivalent to 'select * from {blocktype_sinmpleclock_visit} where blockinstance=$bid and usr=$uid'
        $rec = get_record('blocktype_simpleclock_visit', 'blockinstance',$bid, 'usr',$uid);

        if ( !empty($rec) ) {
            $lastvisit = date("Y/m/d H:i:s",strtotime($rec->lastvisit));
            $count = $rec->countvisit+1;
        } else {
            $count = 1;
        }

        
        // and update the record
        $whereobject = array (
            'blockinstance' => $bid,
            'usr' => $uid
        );

        $dataobject = array (
            'blockinstance' => $bid,
            'usr' => $uid,
            'lastvisit' => $now,
            'countvisit' => $count
        );

        // UPDATE record with $dataobject if $whereobject exists, otherwise INSERT it.
        $status = ensure_record_exists ( 'blocktype_simpleclock_visit', $whereobject, $dataobject );

        $result = get_string('clockstring','blocktype.simpleclock',date("Y/m/d H:i:s"));

        if ( $count == 1 ) {
            $result .= '<br>'.get_string('firstvisit','blocktype.simpleclock');
        } else {
            $result .= '<br>'.get_string('notfirstvisit','blocktype.simpleclock',$lastvisit);
        }

        return $result;
    }

新しくメッセージを追加したので、LANGファイルも書き換えが必要。

lang/en.utf8/blocktype.simpleclock.php

$string['title'] = 'SimpleClock';
$string['description'] = 'Show current date/time on your view.';

$string['clockstring'] = 'It is %s now.';
$string['firstvisit'] = 'Welcome! It\'s your first visit.';
$string['notfirstvisit'] = 'Your last visit: %s';
?>

lang/ja.utf8/blocktype.simpleclock.php

$string['title'] = 'SimpleClock';
$string['description'] = '現在の日付と時刻を表示します。';

$string['clockstring'] = 'ただいまの時刻は %s です。';
$string['firstvisit'] = 'ようこそ!はじめての訪問ですね ^^';
$string['notfirstvisit'] = 'あなたの前回の訪問: %s';
?>

ページに配置してみよう。lib.phpの5-6行目で、編集中にはアクセス記録をつけずに戻るようにしているため、ページに配置した時は以下のようになる。

maharapg-t4-20170903-091742.png

ページ編集モードを抜けて改めて表示すると、以下のようになり、

maharapg-t4-20170903-092137.png

再読み込みすると、以下のようになる。

maharapg-t4-20170903-092219.png

先ほど作成したテーブルの内容を確認すると、レコードが作成、更新されていることがわかる。

maharadb=> select * from blocktype_simpleclock_visit ;
 blockinstance | usr |      lastvisit      | countvisit 
---------------+-----+---------------------+------------
            35 |   1 | 2017-09-03 00:21:48 |          2

ここまでのファイル: filesimpleclock-v2-t4.zip


添付ファイル: filesimpleclock-v2-t4.zip 4件 [詳細]

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-09-04 (月) 10:46:10 (20d)