start-databases.md 13.7 KB
Newer Older
Nobuo Kihara committed
1 2 3 4
データベースを扱う
==================

この節では、`country` という名前のデータベーステーブルから読み出した国データを表示する新しいページの作り方を説明します。
5
この目的を達するために、データベース接続を構成し、[アクティブレコード](db-active-record.md) クラスを作成し、[アクション](structure-controllers.md) を定義し、そして [ビュー](structure-views.md) を作成します。
Nobuo Kihara committed
6

7
このチュートリアルを通じて、次のことを学びます。
Nobuo Kihara committed
8

9 10 11 12
* DB 接続を構成する方法
* アクティブレコードのクラスを定義する方法
* アクティブレコードのクラスを使ってデータを検索する方法
* 改ページを伴う仕方でビューにデータを表示する方法
Nobuo Kihara committed
13 14 15 16 17 18 19 20 21 22

この節を完了するためには、データベースを使うことについて基本的な知識と経験が無ければならないことに注意してください。
具体的に言えば、DB クライアントツールを用いてデータベースを作成する方法と、SQL 文を実行する方法を知っていなければなりません。


データベースを準備する<a name="preparing-database"></a>
----------------------


まず初めに、`yii2basic` という名前のデータベースを作成してください。このデータベースからアプリケーションにデータを読み出すことになります。
23
Yii は多数のデータベース製品に対するサポートを内蔵していますので、作成するデータベースは、SQLite、MySQL、PosttreSQL、MSSQL または Oracle から選ぶことが出来ます。
Nobuo Kihara committed
24 25 26
以下の説明では、話を単純にするために、MySQL を前提とします。

次に、データベースに `country` という名前のテーブルを作り、いくつかのサンプルデータを挿入します。
27
そうするためには、次の SQL 文を実行することが出来ます。
Nobuo Kihara committed
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

```sql
CREATE TABLE `country` (
  `code` CHAR(2) NOT NULL PRIMARY KEY,
  `name` CHAR(52) NOT NULL,
  `population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `country` VALUES ('AU','Australia',18886000);
INSERT INTO `country` VALUES ('BR','Brazil',170115000);
INSERT INTO `country` VALUES ('CA','Canada',1147000);
INSERT INTO `country` VALUES ('CN','China',1277558000);
INSERT INTO `country` VALUES ('DE','Germany',82164700);
INSERT INTO `country` VALUES ('FR','France',59225700);
INSERT INTO `country` VALUES ('GB','United Kingdom',59623400);
INSERT INTO `country` VALUES ('IN','India',1013662000);
INSERT INTO `country` VALUES ('RU','Russia',146934000);
INSERT INTO `country` VALUES ('US','United States',278357000);
```

48
この時点で、あなたは `yii2basic` という名前のデータベースを持ち、その中に三つのカラムを持つ `country` というテーブルがあり、`country` テーブルは 10 行のデータを持っている、ということになります。
Nobuo Kihara committed
49 50


51
DB 接続を構成する<a name="configuring-db-connection"></a>
Nobuo Kihara committed
52 53 54 55 56 57
-----------------

先に進む前に、[PDO](http://www.php.net/manual/en/book.pdo.php) PHP 拡張および使用しているデータベースの PDO ドライバ
(例えば、MySQL のための `pdo_mysql`) の両方をインストール済みであることを確認してください。
アプリケーションがリレーショナルデータベースを使う場合、これは基本的な必要条件です。

58
これらがインストール済みなら、`config/db.php` というファイルを開いて、あなたのデータベースに適合するようにパラメータを変更してください。デフォルトでは、このファイルは下記の記述を含んでいます。
Nobuo Kihara committed
59 60 61 62 63 64 65 66 67 68 69 70 71

```php
<?php

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=yii2basic',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
];
```

72 73 74
この `config/db.php` というファイルは典型的なファイルベースの [構成情報](concept-configurations.md) のツールです。
この構成情報ファイルが [[yii\db\Connection]] インスタンスの作成と初期化に必要なパラメータを規定します。そして、
[[yii\db\Connection]] インスタンスを通じて、背後のデータベースに対する SQL クエリを実行することが出来るようになります。
Nobuo Kihara committed
75

76
上記のようにして構成された DB 接続は、アプリケーションコードの中で `Yii::$app->db` という式でアクセスすることが出来ます。
Nobuo Kihara committed
77

78
> Info|情報: `config/db.php` は、メインのアプリケーション構成情報ファイルである `config/web.php` にインクルードされます。
Nobuo Kihara committed
79
  この `config/web.php`[アプリケーション](structure-applications.md) インスタンスが初期化される仕方を規定します。
80
  詳しい情報については、[構成情報](concept-configurations.md) の節を参照してください。
Nobuo Kihara committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103


アクティブレコードを作成する<a name="creating-active-record"></a>
----------------------------

`country` テーブルの中のデータを表現し取得するために、[アクティブレコード](db-active-record.md) から派生した
`Country` という名前のクラスを作成し、それを `models/Country.php` というファイルに保存します。

```php
<?php

namespace app\models;

use yii\db\ActiveRecord;

class Country extends ActiveRecord
{
}
```

`Country` クラスは [[yii\db\ActiveRecord]] を拡張しています。この中には一つもコードを書く必要はありません。
単に上記のコードだけで、Yii は関連付けられたテーブル名をクラス名から推測します。

104
> Info|情報: クラス名とテーブル名を直接に合致させることが出来ない場合は、[[yii\db\ActiveRecord::tableName()]] メソッドをオーバーライドして、関連づけられたテーブル名を明示的に指定することが出来ます。
Nobuo Kihara committed
105

106
`Country` クラスを使うことによって、以下のコード断片で示すように、`country` テーブルの中のデータを簡単に操作することが出来ます。
Nobuo Kihara committed
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

```php
use app\models\Country;

// country テーブルから全ての行を取得して "name" 順に並べる
$countries = Country::find()->orderBy('name')->all();

// プライマリキーが "US" である行を取得する
$country = Country::findOne('US');

// "United States" を表示する
echo $country->name;

// 国名を "U.S.A." に修正してデータベースに保存する
$country->name = 'U.S.A.';
$country->save();
```

> Info|情報: アクティブレコードは、オブジェクト指向の流儀でデータベースのデータにアクセスし、操作する強力な方法です。
126 127
[アクティブレコード](db-active-record.md) の節で、詳細な情報を得ることが出来ます。
もう一つの方法として、[データアクセスオブジェクト](db-dao.md) と呼ばれる、より低レベルなデータアクセス方法を使ってデータベースを操作することも出来ます。
Nobuo Kihara committed
128 129 130 131 132 133


アクションを作成する<a name="creating-action"></a>
--------------------

国データをエンドユーザに見えるようにするために、新しいアクションを作成する必要があります。
134 135
これまでの節でしたように `site` コントローラの中に新しいアクションを置くのではなく、国データに関係する全てのアクションに限定した新しいコントローラを作成する方が理にかなうでしょう。
この新しいコントローラを `CountryController` と名付けます。そして、下記に示すように、`index` アクションをその中に作成します。
Nobuo Kihara committed
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175


```php
<?php

namespace app\controllers;

use yii\web\Controller;
use yii\data\Pagination;
use app\models\Country;

class CountryController extends Controller
{
    public function actionIndex()
    {
        $query = Country::find();

        $pagination = new Pagination([
            'defaultPageSize' => 5,
            'totalCount' => $query->count(),
        ]);

        $countries = $query->orderBy('name')
            ->offset($pagination->offset)
            ->limit($pagination->limit)
            ->all();

        return $this->render('index', [
            'countries' => $countries,
            'pagination' => $pagination,
        ]);
    }
}
```

上記のコードを `controllers/CountryController.php` というファイルに保存します。

`index` アクションは `Country::find()` を呼び出します。
このアクティブレコードのメソッドは DB クエリを構築して、`country` テーブルから全てのデータを読み出します。
一回のリクエストで返される国の数を制限するために、クエリは [[yii\data\Pagination]] オブジェクトの助けを借りてページ付けされます。
176
`Pagination` オブジェクトは二つの目的に奉仕します。
Nobuo Kihara committed
177

178
* クエリによって表現される SQL 文に `offset` 句と `limit` 句をセットして、一度に一ページ分のデータだけ (1ページ最大5行) を返すようにします。
Nobuo Kihara committed
179 180
* 次の項で説明されるように、一連のページボタンからなるページャをビューに表示するために使われます。

181
コードの最後で、`index` アクションは `index` と言う名前のビューをレンダリングしていますが、このとき、国データはもちろん、そのページ付け情報もビューに渡されます。
Nobuo Kihara committed
182 183 184 185 186 187 188


ビューを作成する<a name="creating-view"></a>
----------------

最初に、`views` ディレクトリの下に `country` という名前のサブディレクトリを作ってください。
このフォルダが `country` コントローラによって表示される全てのビューを保持するのに使われます。
189
`views/country` ディレクトリの中に、下記のコードを含む `index.php` という名前のファイルを作成します。
Nobuo Kihara committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209

```php
<?php
use yii\helpers\Html;
use yii\widgets\LinkPager;
?>
<h1>国リスト</h1>
<ul>
<?php foreach ($countries as $country): ?>
    <li>
        <?= Html::encode("{$country->name} ({$country->code})") ?>:
        <?= $country->population ?>
    </li>
<?php endforeach; ?>
</ul>

<?= LinkPager::widget(['pagination' => $pagination]) ?>
```

ビューは国データの表示に関連して二つの部分に分けられます。
210
最初の部分では、提供された国データがたどられて、HTML の順序無しリストとしてレンダリングされます。
211
第二の部分では、アクションから渡されたページ付け情報を使って、[[yii\widgets\LinkPager]] ウィジェットがレンダリングされます。
Nobuo Kihara committed
212 213 214 215 216 217
`LinkPager` ウィジェットはページボタンのリストを表示します。ボタンのどれかをクリックすると、対応するページの国データが更新表示されます。


試してみる<a name="trying-it-out"></a>
----------

218
上記のコード全てがどのように動作するかを見るために、ブラウザで下記の URL をアクセスします。
Nobuo Kihara committed
219 220 221 222 223 224 225 226 227

```
http://hostname/index.php?r=country/index
```

![国リスト](images/start-country-list.png)

最初、ページは5つの国を表示しています。
そして、国リストの下には、4つのボタンを持ったページャがあります。
228 229
"2" のボタンをクリックすると、ページはデータベースにある次の5つの国、すなわち、2ページ目のレコードを表示します。
注意深く観察すると、ブラウザの URL も次のように変ったことに気付くでしょう。
Nobuo Kihara committed
230 231 232 233 234 235 236

```
http://hostname/index.php?r=country/index&page=2
```

舞台裏では、[[yii\data\Pagination|Pagination]] が、データセットをページ付けするのに必要な全ての機能を提供しています。

237 238
* 初期状態では、[[yii\data\Pagination|Pagination]] は、1ページ目を表しています。
  これを反映して、国の SELECT クエリは `LIMIT 5 OFFSET 0` という句を伴うことになります。
Nobuo Kihara committed
239
  その結果、最初の5つの国が取得されて表示されます。
240
* [[yii\widgets\LinkPager|LinkPager]] ウィジェットは、[[yii\data\Pagination::createUrl()|Pagination]] によって作成された URL を使ってページボタンをレンダリングします。
Nobuo Kihara committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254
  URL は、別々のページ番号を表現する `page` というクエリパラメータを含んだものになります。
* ページボタン "2" をクリックすると、`country/index` のルートに対する新しいリクエストが発行され、処理されます。
  [[yii\data\Pagination|Pagination]] が URL から `page` クエリパラメータを読み取って、カレントページ番号を 2 にセットします。
  こうして、新しい国のクエリは `LIMIT 5 OFFSET 5` という句を持ち、次の5つの国を表示のために返すことになります。


まとめ<a name="summary"></a>
------

この節では、データベースを扱う方法を学びました。
また、[[yii\data\Pagination]] と [[yii\widgets\LinkPager]] の助けを借りて、ページ付けされたデータを取得し表示する方法も学びました。

次の節では、[Gii](tool-gii.md) と呼ばれる強力なコード生成ツールを使う方法を学びます。
このツールは、データベーステーブルのデータを取り扱うための「作成・読出し・更新・削除 (CRUD)」操作のような、通常必要とされることが多いいくつかの機能の迅速な実装を手助けしてくれるものです。
255
実際のところ、あなたがたった今書いたばかりのコードは、Gii ツールを使えば、全部、Yii が自動的に生成してくれるものです。