Commit fcaabbc2 by Nobuo Kihara

docs/guide-ja/input updated [ci skip]

parent 179eea64
...@@ -90,7 +90,8 @@ All Rights Reserved. ...@@ -90,7 +90,8 @@ All Rights Reserved.
* [フォームを作成する](input-forms.md) * [フォームを作成する](input-forms.md)
* [入力を検証する](input-validation.md) * [入力を検証する](input-validation.md)
* [ファイルをアップロードする](input-file-upload.md) * [ファイルをアップロードする](input-file-upload.md)
* **未定** [複数モデルのデータ取得](input-multiple-models.md) * [表形式インプットのデータ収集](input-tabular-input.md)
* [複数モデルのデータ取得](input-multiple-models.md)
データの表示 データの表示
......
フォームを扱う フォームを作成する
============== ==================
> Note|注意: この節はまだ執筆中です。 Yii においてフォームを使用するための主たる方法は [[yii\widgets\ActiveForm]] によるものです。
Yii においてフォームを使用する主たる方法は [[yii\widgets\ActiveForm]] によるものです。
フォームがモデルに基づくものである場合はこの方法を優先すべきです。 フォームがモデルに基づくものである場合はこの方法を優先すべきです。
これに加えて、[[yii\helpers\Html]] にはいくつかの有用なメソッドがあり、通常は、あらゆるフォームにボタンやヘルプテキストを追加するのに使うことが出来ます。 これに加えて、[[yii\helpers\Html]] にはいくつかの有用なメソッドがあり、どんなフォームでもボタンやヘルプテキストを追加するのには、通常はそれらが使われます。
フォームは、クライアント側で表示されるものですが、たいていの場合、サーバ側でフォームの入力を検証するために使われる、対応する [モデル](structure-models.md) を持ちます
(入力の検証の詳細については、[入力を検証する](input-validation.md) の節を参照してください)。
モデルに基づくフォームを作成する場合、最初のステップは、モデルそのものを定義することです。 モデルに基づくフォームを作成する場合、最初のステップは、モデルそのものを定義することです。
モデルは、アクティブレコードクラス、あるいは、もっと汎用的な Model クラスから派生させることが出来ます。 モデルは、データベースの何らかのデータを表現するために [アクティブレコード](db-active-record.md) クラスから派生させるか、あるいは、任意の入力、例えばログインフォームの入力を捕捉するために ([[yii\base\Model]] から派生させた) 汎用的な Model クラスとすることが出来ます。
このログインフォームの例では、汎用的なモデルを使用します。 以下の例においては、ログインフォームのために汎用的なモデルを使う方法を示します。
```php ```php
use yii\base\Model; <?php
class LoginForm extends Model class LoginForm extends \yii\base\Model
{ {
public $username; public $username;
public $password; public $password;
/**
* @return array 検証規則
*/
public function rules() public function rules()
{ {
return [ return [
// username と password はともに必須 // 検証規則をここで定義
[['username', 'password'], 'required'],
// password は validatePassword() によって検証される
['password', 'validatePassword'],
]; ];
} }
/**
* パスワードを検証する
* このメソッドがパスワードのインライン検証に使用される
*/
public function validatePassword()
{
$user = User::findByUsername($this->username);
if (!$user || !$user->validatePassword($this->password)) {
$this->addError('password', 'Incorrect username or password.');
}
}
/**
* 提供された username と password でユーザをログインさせる。
* @return boolean ユーザのログインが成功したかどうか
*/
public function login()
{
if ($this->validate()) {
$user = User::findByUsername($this->username);
return true;
} else {
return false;
}
}
}
``` ```
コントローラはこのモデルのインスタンスをビューに渡し、ビューでは [[yii\widgets\ActiveForm|ActiveForm]] ウィジェットが使われます。 コントローラにおいて、このモデルのインスタンスをビューに渡し、ビューでは [[yii\widgets\ActiveForm|ActiveForm]] ウィジェットがフォームを表示するのに使われます。
```php ```php
<?php
use yii\helpers\Html; use yii\helpers\Html;
use yii\widgets\ActiveForm; use yii\widgets\ActiveForm;
<?php $form = ActiveForm::begin([ $form = ActiveForm::begin([
'id' => 'login-form', 'id' => 'login-form',
'options' => ['class' => 'form-horizontal'], 'options' => ['class' => 'form-horizontal'],
]) ?> ]) ?>
...@@ -83,32 +52,31 @@ use yii\widgets\ActiveForm; ...@@ -83,32 +52,31 @@ use yii\widgets\ActiveForm;
上記のコードでは、[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] がフォームのインスタンスを作成するだけでなく、フォームの開始をマークしています。 上記のコードでは、[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] がフォームのインスタンスを作成するだけでなく、フォームの開始をマークしています。
[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] と [[yii\widgets\ActiveForm::end()|ActiveForm::end()]] の間に置かれた全てのコンテントが `<form>` タグによって囲まれます。 [[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] と [[yii\widgets\ActiveForm::end()|ActiveForm::end()]] の間に置かれた全てのコンテントが `<form>` タグによって囲まれます。
その他のウィジェットと同じように、ウィジェットをどのように構成すべきかに関するオプションを指定するために、`begin` メソッドに配列を渡すことが出来ます。 どのウィジェットでも同じですが、ウィジェットをどのように構成すべきかに関するオプションを指定するために、`begin` メソッドに配列を渡すことが出来ます。
この例では、追加の CSS クラスと要素を特定するための ID が渡されて、開始 `<form>` タグに適用されています。 この例では、追加の CSS クラスと要素を特定するための ID が渡されて、開始 `<form>` タグに適用されています。
利用できるオプションはすべて [[yii\widgets\ActiveForm]] の API ドキュメントに記されていますので参照してください。
フォームの中で、フォームの要素を作成するために、ActiveForm ウィジェットの [[yii\widgets\ActiveForm::field()|ActiveForm::field()]] メソッドが呼ばれています。このメソッドは、要素のラベルと、適用できる JavaScript の検証メソッドがあれば、それらも追加します。 フォームの中では、フォームの要素を作成し、それと一緒に要素のラベルと、そして、適用できる JavaScript の検証メソッドがあれば、それも追加するために、ActiveForm ウィジェットの [[yii\widgets\ActiveForm::field()|ActiveForm::field()]] メソッドが呼ばれています。
このメソッドは、[[yii\widgets\ActiveField]] のインスタンスを返します。
このメソッドの呼び出し結果を直接にエコーすると、結果は通常の (text の) インプットになります。 このメソッドの呼び出し結果を直接にエコーすると、結果は通常の (text の) インプットになります。
出力結果をカスタマイズするためには、このメソッドの呼び出しに追加のメソッドをチェーンします。 出力結果をカスタマイズするためには、このメソッドの呼び出しに追加の [[yii\widgets\ActiveField|ActiveField]] のメソッドをチェーンします。
```php ```php
// パスワードのインプット
<?= $form->field($model, 'password')->passwordInput() ?> <?= $form->field($model, 'password')->passwordInput() ?>
// ヒントとカスタマイズしたラベルを追加
// または
<?= $form->field($model, 'username')->textInput()->hint('お名前を入力してください')->label('お名前') ?> <?= $form->field($model, 'username')->textInput()->hint('お名前を入力してください')->label('お名前') ?>
``` // HTML5 のメールインプット要素を作成
これで、フォームのフィールドによって定義されたテンプレートに従って、`<label>``<input>` など、全てのタグが生成されます。
これらのタグを自分で追加するためには、`Html` ヘルパクラスを使うことが出来ます。
HTML5 のフィールドを使いたい場合は、次のように、インプットのタイプを直接に指定することが出来ます。
```php
<?= $form->field($model, 'email')->input('email') ?> <?= $form->field($model, 'email')->input('email') ?>
``` ```
モデルの属性を指定するためには、もっと洗練された方法を使うことも出来ます。 これで、フォームのフィールドによって定義された [[yii\widgets\ActiveField::$template|テンプレート]] に従って、`<label>``<input>` など、全てのタグが生成されます。
例えば、複数のファイルをアップロードしたり、複数の項目を選択したりする場合に、属性の名前に `[]` を付けて、属性が配列の値を取り得ることを指定することが出来ます。 インプットフィールドの名前は、モデルの [[yii\base\Model::formName()|フォーム名]] と属性から自動的に決定されます。
例えば、上記の例における `username` 属性のインプットフィールドの名前は `LoginForm[username]` となります。
この命名規則の結果として、ログインフォームの全ての属性が配列として、サーバ側においては `$_POST['LoginForm']` に格納されて利用できることになります。
モデルの属性を指定するために、もっと洗練された方法を使うことも出来ます。
例えば、複数のファイルをアップロードしたり、複数の項目を選択したりする場合に、属性の名前に `[]` を付けて、属性が配列の値を取ることが出来ることを指定することが出来ます。
```php ```php
// 複数のファイルのアップロードを許可する // 複数のファイルのアップロードを許可する
...@@ -118,74 +86,24 @@ echo $form->field($model, 'uploadFile[]')->fileInput(['multiple'=>'multiple']); ...@@ -118,74 +86,24 @@ echo $form->field($model, 'uploadFile[]')->fileInput(['multiple'=>'multiple']);
echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']); echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Item B', 'c' => 'Item C']);
``` ```
> **tip**|**ヒント**: 必須フィールドをアスタリスク付きのスタイルにするために、次の CSS を使うことが出来ます。 フォームに HTML タグを追加するためには、素の HTML を使うか、または、上記の例の [[yii\helpers\Html::submitButton()|Html::submitButton()]] のように、[[yii\helpers\Html|Html]] ヘルパクラスのメソッドを使うことが出来ます。
>
```css
div.required label:after {
content: " *";
color: red;
}
```
一つのフォームで複数のモデルを扱う
----------------------------------
時として、一つのフォームで同じ種類の複数のモデルを扱わなければならないことがあります。 > Tip|ヒント: あなたのアプリケーションで Twitter Bootstrap CSS を使っている場合は、[[yii\widgets\ActiveForm]] の代りに [[yii\bootstrap\ActiveForm]] を使うのが良いでしょう。
例えば、それぞれが「名前-値」の形で保存され、`Setting` モデルとして表される複数の設定項目を扱うフォームです。 > これは ActiveForm クラスのエクステンションであり、bootstrap CSS フレームワークで使用するための追加のスタイルをサポートしています。
以下に、これを Yii で実装する方法を示します。
コントローラアクションから始めましよう。 > tip|ヒント: 必須フィールドをアスタリスク付きのスタイルにするために、次の CSS を使うことが出来ます。
>
```php >```css
namespace app\controllers; >div.required label:after {
> content: " *";
use Yii; > color: red;
use yii\base\Model; >}
use yii\web\Controller; >```
use app\models\Setting;
class SettingsController extends Controller
{
// ...
public function actionUpdate()
{
$settings = Setting::find()->indexBy('id')->all();
if (Model::loadMultiple($settings, Yii::$app->request->post()) && Model::validateMultiple($settings)) {
foreach ($settings as $setting) {
$setting->save(false);
}
return $this->redirect('index');
}
return $this->render('update', ['settings' => $settings]);
}
}
```
上記のコードでは、データベースからモデルを読み出すときに `indexBy` を使って、モデルの ID でインデックスされた配列にモデルを代入しています。
このインデックスが、後で、フォームフィールドを特定するために使われます。
`loadMultiple` が POST から来るフォームデータを複数のモデルに代入し、`validateMultiple` が全てのモデルを一度に検証します。
保存するときの検証をスキップするために、`save` のパラメータに `false` を渡しています。
次に、`update` ビューにあるフォームです。
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin();
foreach ($settings as $index => $setting) { 次の節 [入力を検証する](input-validation.md) は、送信されたフォームデータのサーバ側でのバリデーションと、ajax バリデーションおよびクライアント側バリデーションを扱います。
echo Html::encode($setting->name) . ': ' . $form->field($setting, "[$index]value");
}
ActiveForm::end(); フォームのもっと複雑な使用方法については、以下の節を読んで下さい。
```
ここで全ての設定項目について、それぞれ、名前と値を入れたインプットをレンダリングしています - [表形式インプットのデータ収集](input-tabular-input.md) - 同じ種類の複数のモデルのデータを収集する
インプットの名前に適切なインデックスを追加することが肝腎です - [複数のモデルを持つ複雑なフォーム](input-multiple-models.md) - 同じフォームの中で複数の異なるモデルを扱う
というのは、`loadMultiple` がそれを見て、どのモデルにどの値を代入するかを決定するからです - [ファイルをアップロードする](input-file-upload) - フォームを使ってファイルをアップロードする方法
複数のモデルを扱う複雑なフォーム 複数のモデルを扱う複雑なフォーム
================================ ================================
複雑なユーザインタフェイスにおいては、一つのフォームにユーザが入力したデータをデータベースの異なる複数のテーブルに保存しなければならないということが生じ得ます。
Yii のフォームの概念に従うと、単一モデルのフォームと比べても、ほとんど複雑さを加えることなく、そういうフォームを構築することが出来ます。
単一モデルの場合と同じように、サーバ側では次のような検証のスキーマに従います。
1. モデルのクラスをインスタンス化する。
2. モデルの属性に入力されたデータを投入する。
3. 全てのモデルを検証する。
4. 全てのモデルに対して検証が通った場合は、それらを保存する。
5. 検証が失敗した場合、または、データが送信されなかった場合は、全てのモデルのインスタンスをビューに渡してフォームを表示する。
次に、一つのフォームで複数のモデルを使用する例を示します ... (未定)
複数のモデルの例
----------------
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
(未定)
依存するモデル
--------------
> Note|注意: この節はまだ執筆中です。 > Note|注意: この節はまだ執筆中です。
> >
> まだ内容がありません。 > まだ内容がありません。
(未定)
表形式インプットでデータを収集する
==================================
時として、一つのフォームで同じ種類の複数のモデルを扱わなければならないことがあります。
例えば、それぞれが「名前-値」の形で保存され、`Setting` [アクティブレコード](db-active-record.md) モデルとして表される複数の設定項目を扱うフォームです。
この種のフォームは「表形式インプット」と呼ばれることもよくあります。
これとは対照的な、異なる種類のさまざまなモデルを扱うことについては、[複数のモデルを持つ複雑なフォーム](input-multiple-models.md) の節で扱います。
以下に、表形式インプットを Yii で実装する方法を示します。
カバーすべき三つの異なる状況があり、それぞれ少しずつ異なる処理をしなければなりません。
- 特定の数のデータベースレコードを更新する
- 不特定の数の新しいレコードを作成する
- 一つのページでレコードを更新、作成、および、削除する
前に説明した単一モデルのフォームとは対照的に、モデルの配列を扱うことになります。
この配列がビューに渡されて、各モデルのためのインプットフィールドが表のような形式で表示され、そして、複数のモデルを一度にロードしたり検証したりするために [[yii\base\Model]] のヘルパメソッドを使用します。
- [[yii\base\Model::loadMultiple()|Model::loadMultiple()]] - 送信されたデータをモデルの配列にロードします。
- [[yii\base\Model::validateMultiple()|Model::validateMultiple()]] - モデルの配列を検証します。
### 特定の数のレコードを更新する
コントローラのアクションから始めましょう。
```php
<?php
namespace app\controllers;
use Yii;
use yii\base\Model;
use yii\web\Controller;
use app\models\Setting;
class SettingsController extends Controller
{
// ...
public function actionUpdate()
{
$settings = Setting::find()->indexBy('id')->all();
if (Model::loadMultiple($settings, Yii::$app->request->post()) && Model::validateMultiple($settings)) {
foreach ($settings as $setting) {
$setting->save(false);
}
return $this->redirect('index');
}
return $this->render('update', ['settings' => $settings]);
}
}
```
上記のコードでは、データベースからモデルを読み出すときに [[yii\db\ActiveQuery::indexBy()|indexBy()]] を使って、モデルのプライマリキーでインデックスされた配列にデータを投入しています。
このインデックスが、後で、フォームフィールドを特定するために使われます。
[[yii\base\Model::loadMultiple()|Model::loadMultiple()]] が POST から来るフォームデータを複数のモデルに代入し、[[yii\base\Model::validateMultiple()|Model::validateMultiple()]] が全てのモデルを一度に検証します。
保存するときには、`validateMultiple()` を使ってモデルの検証を済ませていますので、[[yii\db\ActiveRecord::save()|save()]] のパラメータに `false` を渡して、二度目の検証を実行しないようにしています。
次に、`update` ビューにあるフォームです。
Now the form that's in `update` view:
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin();
foreach ($settings as $index => $setting) {
echo $form->field($setting, "[$index]value")->label($setting->name);
}
ActiveForm::end();
```
ここで全ての設定項目について、それぞれ、項目名を示すラベルと、項目の値を入れたインプットをレンダリングしています。
インプットの名前に適切なインデックスを追加することが肝腎です。
というのは、`loadMultiple` がそれを見て、どのモデルにどの値を代入するかを決定するからです。
### 不特定の数の新しいレコードを作成する
新しいレコードを作成するのは、モデルのインスタンスを作成する部分を除いて、更新の場合と同じです。
```php
public function actionCreate()
{
$count = count(Yii::$app->request->post('Setting', []));
$settings = [new Setting()];
for($i = 1; $i < $count; $i++) {
$settings[] = new Setting();
}
// ...
}
```
ここでは、デフォルトで一個のモデルを含む `$settings` 配列を初期値として作成し、少なくとも一個のテキストフィールドが常にビューに表示されるようにしています。
そして、受信したインプットの行数に合せて、配列にモデルを追加しています。
ビューでは javascript を使ってインプットの行を動的に追加することが出来ます。
### 更新、作成、削除を一つのページに組み合わせる
> Note|注意: この節はまだ執筆中です。
>
> まだ内容がありません。
(未定)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment