フォームを扱う
==============

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

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

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

* フォームを通じてユーザが入力したデータを表す [モデル](structure-models.md) を作成する
* 入力されたデータを検証する規則を宣言する
* [ビュー](structure-views.md) の中で HTML フォームを構築する


モデルを作成する<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) を使います。
ウィジェットの `begin()` メソッドと `end()` メソッドが、それぞれ、フォームの開始タグと終了タグを表示します。
この二つのメソッドの呼び出しの間に、[[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 はこの作業を非常に容易にする強力なウィジェットを提供しています。

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