Skip to content

4.データベースの接続

Akito edited this page Aug 8, 2013 · 5 revisions

いよいよEnviからDBに接続してみます。

このページでの目標

  1. EnviからDBに接続する
  2. フォームから入力された値をDBに保存する
  3. データベースから取り出した値を値をテンプレートで表示する

データベースの設定

接続先の設定

config/bbs_databases.yml を見てみましょう。 ここには、データベースへの接続情報がYAML形式で記述されています。

all:
  default_master:
    params:
      dsn: "phptype=mysql&username=exampleuser&password=example&hostspec=localhost&database=example_master"
      instance_pool: true
      connection_pool: false
      initialize_query: "set names utf8;"
  default_slave:
    params:
      dsn: "phptype=mysql&username=exampleuser&password=example&hostspec=localhost&database=example_slave"
      instance_pool: true
      connection_pool: false
      initialize_query: "set names utf8;"
  default_stage:
    params:
      dsn: "phptype=mysql&username=exampleuser&password=example&hostspec=localhost&database=example_stage"
      instance_pool: true
      connection_pool: false
      initialize_query: "set names utf8;"

今回は、default_masterの項目を修正して、DBの設定を作成します。 default_slavedefault_stageは使用しないので、削除するか、単に無視してください。 複数のDBに接続する必要が有る場合は、default_slavedefault_stageのように複数の設定を記述することもできます。

paramsのそれぞれの項目は、

  • dsn DB接続用のDSNを記載します
  • instance_pool DBを接続したオブジェクトをプールするかどうかを決定します。 trueでオブジェクトの生成を1回のみとします。
  • connection_pool コネクションプーリングを有効にするかどうかを決定します。 trueで有効となります。
  • initialize_query 接続時に自動で発行するクエリを記述します。 必要がない場合は空にしておいてください。単に無視されます。

テーブル定義の設定

次にconfig/bbs_schema.yml を見てみましょう。 ここには、アプリケーション内で使用するテーブルの定義が記載されています。 これを、下記のように修正します。

SCHEMA:
  ## <?php $app_name = substr(basename(__FILE__), 0, strlen(basename(__FILE__))-strlen('_schema.yml')); ?>
  # テーブル名
  bbs:
    schema:
      bbs_id:
        type: int(11)
        default: null
        primary: PRIMARY
        not_null: true
        auto_increment: true
      name:
        type: varchar(255)
        not_null: true
        default: null
      email:
        type: varchar(255)
        default: null
      comment_text:
        type: longtext
        not_null: true
        default: null
      insert_date:
        type: datetime
        default: null
        not_null: true
      time_stamp:
        type: timestamp
        default: null
        not_null: true

DIRECTORY:
  # モデルを保存するdirectory
  model_dir: "<?php $ds = DIRECTORY_SEPARATOR; echo realpath(ENVI_BASE_DIR."..{$ds}..{$ds}apps{$ds}{$app_name}{$ds}libs{$ds}models").$ds; ?>"

SETTING:
  #デフォルトのインスタンス名
  default_instance_name: "default_master"
  #マジックメソッドを利用したSetterGetterを使用するかどうか
  default_magic_method: false
  # データーベース定義
  database_yaml: "<?php echo realpath(ENVI_BASE_DIR."..{$ds}..{$ds}config{$ds}").$ds.$app_name?>_databases.yml"
  # 環境
  env: "dev"
  # デフォルトのauto_schema
  default_auto_schema: false
  # auto_schemaの結果を反映した、yamlファイルを出力するかどうか
  reverse_yaml: false

修正したら、

envi build-query config/bbs_schema.yml

と打ってみましょう。

DROP TABLE IF EXISTS `bbs`;
CREATE TABLE `bbs` (
`bbs_id` int(11) NOT NULL  AUTO_INCREMENT,
`name` varchar(255) NOT NULL ,
`email` varchar(255) ,
`comment_text` longtext NOT NULL ,
`insert_date` datetime NOT NULL ,
`time_stamp` timestamp NOT NULL ,
PRIMARY KEY (bbs_id)) ENGINE=InnoDB;

Mysql準拠のCREATE文が発行されました。

これを使用してテーブルを作ってみてください。

mysql>     CREATE TABLE `bbs` (
    ->     `bbs_id` int(11) NOT NULL  AUTO_INCREMENT,
    ->     `name` varchar(255) NOT NULL ,
    ->     `email` varchar(255) ,
    ->     `comment_text` longtext NOT NULL ,
    ->     `insert_date` datetime NOT NULL ,
    ->     `time_stamp` timestamp NOT NULL ,
    ->     PRIMARY KEY (bbs_id)) ENGINE=InnoDB;
Query OK, 0 rows affected (0.04 sec)

できましたか?

テーブルができたら、次は、モデルの作成です。 今度は、

envi build-model config/bbs_schema.yml

と打ってみましょう。

/apps/bbs/libs/models//om/BaseBbsPeer.class.php
/apps/bbs/libs/models//om/BaseBbs.class.php
/apps/bbs/libs/models//Bbs.class.php
/apps/bbs/libs/models//BbsPeer.class.php

4つのファイルができましたか?

BbsPeerに掲示板書き込みの処理を追加する

~Peerには、SQL文や、OrMapオブジェクトへの複雑な操作などを static で記述します。
早速、 /apps/bbs/libs/models//BbsPeer.class.php に書き込みの処理を追加してみましょう。

/**
 * +-- bbsテーブルに書き込む
 *
 * @static
 * @access public
 * @param string $name 名前
 * @param string $email メールアドレス
 * @param string $comment_text コメント
 * @return boolean
 */
public static function write($name, $email, $comment_text)
{
    try{
        $bbs = new Bbs;
        $bbs->setName($name);
        $bbs->setEmail($email);
        $bbs->setCommentText($comment_text);
        $bbs->setInsertDate(date('Y-m-d H:i:s'));
        $bbs->save();
    } catch (Exception $e) {
        return false;
    }
    return true;
}
/* ----------------------------------------- */

テーブルに対して、Insertを行うのは非常に簡単です。
該当するテーブルのオブジェクトを new し、値をsetし set するだけです。

トランザクションを貼りたい場合は、

/**
 * +-- bbsテーブルに書き込む
 *
 * @static
 * @access public
 * @param string $name 名前
 * @param string $email メールアドレス
 * @param string $comment_text コメント
 * @return boolean
 */
public static function write($name, $email, $comment_text)
{
    $dbi = extension()->DBI()->getInstance('default_master');
    $dbi->beginTransaction();
    try{
        $bbs = new Bbs;
        $bbs->setName($name);
        $bbs->setEmail($email);
        $bbs->setCommentText($comment_text);
        $bbs->setInsertDate(date('Y-m-d H:i:s'));
        $bbs->save($dbi);
        $dbi->commit();
    } catch (Exception $e) {
        $dbi->roleback();
        return false;
    }
    return true;
}
/* ----------------------------------------- */

このようになります。

アクションから、 BbsPeer::write() をコールする

/apps/bbs/modules/index/actions/indexAction.class.php を開いて、executeを下記のように変更します。

/**
 * +-- validate()でEnvi::SUCCESSもしくはtrueが返った場合の処理。
 *
 * @see validate()
 * @return Envi::DEFAULT | Envi::ERROR | Envi::SUCCESS | boolean
 */
public function execute()
{
    $name         = Request::getAttribute('name');
    $email        = Request::getAttribute('email');
    $comment_text = Request::getAttribute('comment_text');
    if (!BbsPeer::write($name, $email, $comment_text)) {
        validator()->error()->setErrorMess('bbs_write', 'bbs_write', '書き込みに失敗した。');
        return $this->handleError();
    }
    Controller::redirect($_SERVER['SCRIPT_NAME']);
    return Envi::NONE;
}
/* ----------------------------------------- */

投稿してみる

実際にフォームから投稿してみましょう。
問題なく投稿された場合は、エラーメッセージが表示されること無く、
http://bbs.example.jp/bbs.php
にリダイレクトされます。

正常にDBにインサートされているか、直接DBを参照して確認してみてください。

mysql> select * from bbs\G
*************************** 1. row ***************************
      bbs_id: 1
        name: example name
       email: test@test.jp
comment_text: test comment
 insert_date: 2012-07-18 05:31:21
  time_stamp: 2012-07-18 05:31:21
1 row in set (0.00 sec)

書き込み内容を、DBからセレクトする

今度は、 /apps/bbs/libs/models//BbsPeer.class.php にSelectの処理を記述しましょう。
今回はページャーを用意せず、bbs_id降順で、1000件を取得して表示するという形にします。

public static function get()
{
    $dbi = extension()->DBI()->getInstance('default_master');
    $sql = 'SELECT name,email,comment_text,insert_date FROM bbs ORDER BY bbs_id DESC LIMIT 1000';
    $res = $dbi->getAll($sql);
    return is_array($res) ? $res : array();
}

/apps/bbs/libs/models//BbsPeer.class.phpに追加したら、
/apps/bbs/modules/index/actions/indexAction.class.php を開いて、defaultAccessを下記のように変更し、BbsPeer::get() をコールします。

public function defaultAccess()
{
    Request::setAttribute('bbs_data', BbsPeer::get());
    return Envi::DEFAULT_ACCESS;
}

/apps/bbs/modules/index/templates/index.tplを 下記のように変更し、Selectした値を表示します。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
	<title>BBS</title>
</head>

<body>
<?php
if (isset($error)) {
	foreach ($error['message'] as $val) {
        echo htmlspecialchars($val);
	}
}
?>
<br />

<form action="/bbs.php" method="post">

名前:<input type="text" name="name" /><br />
Email:<input type="text" name="email" /><br />
<textarea name="comment_text"></textarea><br />
<br />
<input type="submit" name="commit" value="送信" />


</form>

<?php
if (isset($bbs_data)) {
    foreach ($bbs_data as $val) {
        $val = array_filter($val, 'htmlspecialchars');
        if (!isset($val['email'])) {
            $val['email'] = '';
        }
        echo <<<EOD
■{$val['name']}<br />
<a href="mailto:{$val['email']}">{$val['email']}</a><br />
{$val['comment_text']}<br />

{$val['insert_date']}
<hr />
EOD;
    }
}
?>

</body>
</html>

いかがでしたでしょうか?以上で、掲示板の作成が一通り終わりました。
チュートリアルの最後に、5.動作概要を参照してください。