start-forms.md 12.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
フォームを扱う
==============

この節では、ユーザからデータを取得するフォームを持つ新しいページを作る方法を説明します。
このページは名前の入力フィールドとメールの入力フィールドを持つフォームを表示します。
ユーザからこれら二つの情報を受け取った後、ページは確認のために入力された値をエコーバックします。

この目的を達するために、一つの [アクション](structure-controllers.md) と 二つの [ビュー](structure-views.md) を作成する以外に、
一つの [モデル](structure-models.md) をも作成します。

Nobuo Kihara committed
11
このチュートリアルを通じて、次のことをする方法を学びます:
12

Nobuo Kihara committed
13 14 15
* フォームを通じてユーザが入力したデータを表す [モデル](structure-models.md) を作成する
* 入力されたデータを検証する規則を宣言する
* [ビュー](structure-views.md) の中で HTML フォームを構築する
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 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 173 174


モデルを作成する<a name="creating-model"></a>
----------------

ユーザからの入力を要求するデータは下に示されているように `EntryForm` モデルクラスとして表現され、`models/EntryForm.php` というファイルに保存されます。
クラスファイルの命名規約についての詳細は [クラスのオートロード](concept-autoloading.md) の節を参照してください。

```php
<?php

namespace app\models;

use yii\base\Model;

class EntryForm extends Model
{
    public $name;
    public $email;

    public function rules()
    {
        return [
            [['name', 'email'], 'required'],
            ['email', 'email'],
        ];
    }
}
```

このクラスは、Yii によって提供される基底クラス [[yii\base\Model]] を拡張するものです。
通常、この基底クラスがフォームデータを表現するのに使われます。

> Info|情報: [[yii\base\Model]] はデータベーステーブルと関連*しない*モデルクラスの親として使われます。
データベーステーブルと対応するモデルクラスでは、通常は [[yii\db\ActiveRecord]] が親になります。

`EntryForm` クラスは二つのパブリックメンバー、`name``email` を持っており、これらがユーザによって入力されたデータを保管するのに使われます。
このクラスはまた `rules()` という名前のメソッドを持っています。このメソッドがデータを検証する一連の規則を返します。
上記で宣言されている検証規則は次のことを述べています:

* `name``email` は、ともに値を要求される
* `email` のデータは構文的に正当なメールアドレスでなければならない

`EntryForm` オブジェクトにユーザが入力したデータを投入した後、[[yii\base\Model::validate()|validate()]] を呼んでデータ検証ルーチンを始動することが出来ます。
データ検証が失敗すると [[yii\base\Model::hasErrors|hasErrors]] プロパティが true に設定され、
そして、[[yii\base\Model::getErrors|errors]] を通じて、どのような検証エラーが発生したかを知ることが出来ます。


```php
<?php
$model = new EntryForm();
$model->name = 'Qiang';
$model->email = 'bad';
if ($model->validate()) {
    // 良し!
} else {
    // 失敗!
    // $model->getErrors() を使う
}
```


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

次に、この新しいモデルを使う `entry` アクションを `site` コントローラに作る必要があります。
アクションを作成して使うプロセスについては、すでに [「こんにちは」と言う](start-hello.md) の節で説明されました。

```php
<?php

namespace app\controllers;

use Yii;
use yii\web\Controller;
use app\models\EntryForm;

class SiteController extends Controller
{
    // ... 既存のコード ...

    public function actionEntry()
    {
        $model = new EntryForm;

        if ($model->load(Yii::$app->request->post()) && $model->validate()) {
            // $model に受け取ったデータを検証する

            // ここで $model について意味のあることを何かする ...

            return $this->render('entry-confirm', ['model' => $model]);
        } else {
            // ページの初期表示か、または、何か検証エラーがある
            return $this->render('entry', ['model' => $model]);
        }
    }
}
```

アクションは最初に `EntryForm` オブジェクトを生成します。そして、次に、モデルに `$_POST` のデータ、
Yii においては [[yii\web\Request::post()]] によって提供されるデータを投入しようと試みます。
モデルへのデータ投入が成功した場合(つまり、ユーザが HTML フォームを送信した場合)、アクションは
[[yii\base\Model::validate()|validate()]] を呼んで、入力された値が有効なものであることを確認します。

> Info|情報: `Yii::$app` という式は [アプリケーション](structure-applications.md) インスタンスを表現します。
  これはグローバルにアクセス可能なシングルトンです。これは、また、特定の機能性をサポートする `request`
  `response`, `db` などのコンポーネントを提供する [サービスロケータ](concept-service-locator.md) でもあります。
  上記のコードでは、アプリケーションインスタンスの`request` コンポーネントが `$_POST` データにアクセスするために使われています。

すべてが適正である場合、アクションは `entry-confirm` という名前のビューを表示して、データの送信が成功したことをユーザに確認させます。
データが送信されなかったり、データがエラーを含んでいたりする場合は、`entry` ビューが表示され、その中で HTML フォームが
(もし有れば)検証エラーのメッセージとともに表示されます。

> Note|注意: この簡単な例では、有効なデータ送信に対して単純に確認ページを表示しています。実際の仕事では、
  [フォーム送信の諸問題](http://en.wikipedia.org/wiki/Post/Redirect/Get) を避けるために、
  [[yii\web\Controller::refresh()|refresh()]] または [[yii\web\Controller::redirect()|redirect()]] を使うことを考慮すべきです。


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

最後に、`entry-confirm``entry` と言う名前の二つのビューファイルを作成します。
今まさに説明したように、これらが `entry` アクションによって表示されます。

`entry-confirm` ビューは単純に名前とメールのデータを表示するものです。このビューは `views/site/entry-confirm.php` というファイルに保存しなければなりません。

```php
<?php
use yii\helpers\Html;
?>
<p>あなたは次の情報を入力しました:</p>

<ul>
    <li><label>名前</label>: <?= Html::encode($model->name) ?></li>
    <li><label>メール</label>: <?= Html::encode($model->email) ?></li>
</ul>
```

`entry` ビューは HTML フォームを表示します。これは `views/site/entry.php` というファイルに保存しなければなりません。

```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
?>
<?php $form = ActiveForm::begin(); ?>

    <?= $form->field($model, 'name') ?>

    <?= $form->field($model, 'email') ?>

    <div class="form-group">
        <?= Html::submitButton('送信', ['class' => 'btn btn-primary']) ?>
    </div>

<?php ActiveForm::end(); ?>
```

このビューは HTML フォームを構築するのに、[[yii\widgets\ActiveForm|ActiveForm]] と呼ばれる強力な [ウィジェット](structure-widgets.md) を使います。
175
ウィジェットの `begin()` メソッドと `end()` メソッドが、それぞれ、フォームの開始タグと終了タグをレンダリングします。
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
この二つのメソッドの呼び出しの間に、[[yii\widgets\ActiveForm::field()|field()]] メソッドによって入力フィールドが作成されます。
最初の入力フィールドは "name" のデータ、第二の入力フィールドは "email" のデータのためのものです。
入力フィールドの後に、[[yii\helpers\Html::submitButton()]] メソッドが呼ばれて、送信ボタンを生成しています。


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

どのように動作するかを見るために、ブラウザで下記の URL をアクセスしてください:

```
http://hostname/index.php?r=site/entry
```

二つの入力フィールドを持つフォームを表示するページが表示されるでしょう。
それぞれの入力フィールドの前には、どんなデータを入力すべきかを示すラベルがあります。
何も入力せずに、あるいは、無効なメールアドレスを入力して送信ボタンをクリックすると、
それぞれ問題のある入力フィールドの続きにエラーメッセージが表示されます。

![検証エラーのあるフォーム](images/start-form-validation.png)

有効な名前とメールアドレスを入力してから送信ボタンをクリックすると、たった今入力したデータを表示する新しいページが表示されます。

![データ入力の確認](images/start-entry-confirmation.png)


### 魔法の説明<a name="magic-explained"></a>

あなたは、舞台裏で HTML フォームがどのように動いているのか、不思議に思うかも知れません。なぜなら、
フォームが、ほとんど魔法のように、各入力フィールドのラベルを表示し、データを正しく入力しない場合には
ページをリロードすることなくエラーメッセージを表示するからです。

そう、データの検証は、最初に JavaScript を使ってクライアントサイドで実行され、次に PHP によってサーバーサイドで実行されます。
[[yii\widgets\ActiveForm]] は、賢いことに、`EntryForm` で宣言した検証規則を抽出し、それを実行可能な JavaScript コードに変換して、
JavaScript を使ってデータ検証を実行します。
ブラウザで JavaScript を無効にした場合でも、`actionEntry()` メソッドで示されているように、サーバーサイドでの検証は実行されます。
これにより、どのような状況であっても、データの有効性が保証されます。

> Warning|警告: クライアントサイドの検証は、ユーザにとってのより良い使い心地のために利便性を提供するものです。
  クライアントサイドの検証の有無にかかわらず、サーバサードの検証は常に必要とされます。

入力フィールドのラベルは、モデルのプロパティ名を使用して、`field()` メソッドによって生成されます。
例えば、`name` というプロパティから `Name` というラベルが生成されます。

ビューの中で、下記のコードのように、ラベルをカスタマイズすることも出来ます:

```php
<?= $form->field($model, 'name')->label('お名前') ?>
<?= $form->field($model, 'email')->label('メールアドレス') ?>
```

> Info|情報: Yii はこのようなウィジェットを数多く提供して、複雑で動的なビューを素速く作成することを手助けしてくれます。
  後で学ぶように、新しいウィジェットを書くことも非常に簡単です。
  あなたは、将来のビュー開発を単純化するために、多くのビューコードを再利用可能なウィジェットに変換したいと思うことでしょう。


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

ガイドのこの節においては、MVC デザインパターンの全ての部分に触れました。
そして、ユーザデータを表現し、当該データを検証するモデルクラスを作成する方法を学びました。

また、ユーザからデータを取得する方法と、ブラウザにデータを表示して返す方法も学びました。
この作業は、アプリケーションを開発するときに、多大な時間を必要とするものになり得るものです。
しかし、Yii はこの作業を非常に容易にする強力なウィジェットを提供しています。

次の節では、ほとんど全てのアプリケーションで必要とされるデータベースを取り扱う方法を学びます。