スケジュール入力用のフォームが表示できたので、こんどはデータを保存出来るようにしてみましょう。
「どんなデータベースを使うのが良いか?」で見たように、データ量がごく少量でアクセスも少ないならS式のままファイルに格納する方法がまず考えられます。また、大量のデータを扱うにはRDBMSを使う方法もあります。
ここではRDBMSを使うまでもないデータ量であると判断し、dbm.fsdbmライブラリを使うことにします。
(use dbm.fsdbm)
(define *db-name* "/home/yasuyuki/data/schedule.data")
(use dbm.fsdbm)を評価させてdbm.fsdbmライブラリが使えるようにしておきます。データの保存場所のフルパス名に*db-name*という名前をつけておきます。
(define (cmd-show-plan y m d)
(let* ((db (dbm-open <gdbm> :path *db-name* :rw-mode :write))
(plan (dbm-get db #`",|y|-,|m|-,|d|" "")))
(dbm-close db)
(page
(calendar (make-month m y))
(html:form
(html:p #`",|y|年,|m|月,|d|日の予定")
(html:input :type "hidden" :name "c" :value "e")
(html:input :type "hidden" :name "y" :value (x->string y))
(html:input :type "hidden" :name "m" :value (x->string m))
(html:input :type "hidden" :name "d" :value (x->string d))
(html:p (html:textarea :rows 8 :cols 40 :name "p"
(html-escape-string plan)))
(html:p (html:input :type "submit" :name "submit" :value "変更"))))))
「dbmデータベースからデータを検索する」で説明した方法で、スケジュールデータを日付をキーにして読み込むようにcmd-show-plan手続きを書き直しました。textareaにはデータベースから読み込んだplan を表示します。
スケジュール入力フォームに入力された予定データを受け取るにはどうしたらよいでしょうか?
予定データを受け取れるようにmain手続きを書き直しましょう。
(define (main args)
(cgi-main
(lambda (params)
(let ((y (cgi-get-parameter "y" params :convert x->integer))
(m (cgi-get-parameter "m" params :convert x->integer))
(d (cgi-get-parameter "d" params :convert x->integer))
(cmd (cgi-get-parameter "c" params))
(plan (cgi-get-parameter "p" params
:convert (cut ces-convert <> "*JP"))))
(cgi-output-character-encoding 'utf-8)
(if (and y m d)
(if (equal? cmd "e")
(cmd-change-plan y m d plan)
(cmd-show-plan y m d))
(cmd-show-calendar y m))
))))
パラメータcに"e"が渡されたとき、パラメータpの値を引数にcmd-change-plan手続きを評価しています。
cgi-get-parameter手続きに:convertオプションを渡して入力された文字コードを自動判定して変換しています。
CGIで扱う文字コードも明示的に指定しておきます。上記ではcgi-output-character-encoding手続きを使ってUTF-8を指定しています。
:convertの右に書かれた(cut ces-convert <> "*JP")は次の式に展開されます。
(lambda (x) (ces-convert x "*JP"))
cutは手続きを作り出します。もちろんlambdaでも書けますが、cutを使うと記述が簡潔になります。
「文字コードを変換する」で見たように、ces-convert手続きに"*JP"オプションを指定すると、入力文字列が日本語であるとみなし、文字コードを自動判定して変換してくれます。
データの保存はcmd-change-plan手続きで行います。
(define (cmd-change-plan y m d plan)
(let* ((db (dbm-open <gdbm> :path *db-name* :rw-mode :write)))
(dbm-put! db #`",|y|-,|m|-,|d|" plan)
(dbm-close db)
(cgi-header :status "302 Moved"
:location #`"?y=,|y|&m=,|m|&d=,|d|")))
「dbmデータベースにデータを書き込む」で説明したdbi-put!手続きを使って、日付をキーにして予定データを書き込んでいます。
最後にHTTPステータス"302 Moved"を返してリダイレクトしているのは、フォームを再読み込みされたときに2回以上POSTされるのを防ぐためです。
by えんどうやすゆき