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

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


18
データベースを準備する <span id="preparing-database"></span>
Nobuo Kihara committed
19 20 21
----------------------

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

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

```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);
```

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


50
DB 接続を構成する <span id="configuring-db-connection"></span>
Nobuo Kihara committed
51 52
-----------------

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

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

```php
<?php

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

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

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

76 77
> Info|情報: `config/db.php` は、メインのアプリケーション構成情報ファイルである `config/web.php` によってインクルードされます。
  この `config/web.php`[アプリケーション](structure-applications.md) インスタンスが初期化される仕方を指定するものです。
78
  詳しい情報については、[構成情報](concept-configurations.md) の節を参照してください。
Nobuo Kihara committed
79 80


81
アクティブレコードを作成する <span id="creating-active-record"></span>
Nobuo Kihara committed
82 83
----------------------------

84
`country` テーブルの中のデータを表現し取得するために、[アクティブレコード](db-active-record.md) から派生した `Country` という名前のクラスを作成し、それを `models/Country.php` というファイルに保存します。
Nobuo Kihara committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

```php
<?php

namespace app\models;

use yii\db\ActiveRecord;

class Country extends ActiveRecord
{
}
```

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

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

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

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


127
アクションを作成する <span id="creating-action"></span>
Nobuo Kihara committed
128 129
--------------------

130
国データをエンドユーザに公開するために、新しいアクションを作成する必要があります。
131 132
これまでの節でしたように `site` コントローラの中に新しいアクションを置くのではなく、国データに関係する全てのアクションに限定した新しいコントローラを作成する方が理にかなうでしょう。
この新しいコントローラを `CountryController` と名付けます。そして、下記に示すように、`index` アクションをその中に作成します。
Nobuo Kihara committed
133 134 135 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


```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]] オブジェクトの助けを借りてページ付けされます。
173
`Pagination` オブジェクトは二つの目的に奉仕します。
Nobuo Kihara committed
174

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

178 179
コードの最後で、`index` アクションは `index` と言う名前のビューをレンダリングしています。
このとき、国データだけでなく、そのページネーション情報がビューに渡されます。
Nobuo Kihara committed
180 181


182
ビューを作成する <span id="creating-view"></span>
Nobuo Kihara committed
183 184 185 186
----------------

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

```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]) ?>
```

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


213
試してみる <span id="trying-it-out"></span>
Nobuo Kihara committed
214 215
----------

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

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

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

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

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

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

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


245
まとめ <span id="summary"></span>
Nobuo Kihara committed
246 247 248 249 250 251 252
------

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

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