位置:首頁 > 框架 > Yii2教學 > 使用表單

使用表單

使用表單

本章節將介紹如何創建一個從用戶那搜集數據的表單頁。該頁將顯示一個包含 name 輸入框和 email 輸入框的表單。當搜集完這兩部分信息後,頁麵將會顯示用戶輸入的信息。

為了實現這個目標,除了創建一個[操作]和兩個[視圖]外,還需要創建一個[模型]。

貫穿整個小節,你將會學到:

* 創建一個[模型](structure-models.md)代表用戶通過表單輸入的數據
* 聲明規則去驗證輸入的數據
* 在[視圖](structure-views.md)中生成一個 HTML 表單

創建模型 ​

模型類 `EntryForm` 代表從用戶那請求的數據,該類如下所示並存儲在 `models/EntryForm.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\base\Model]],Yii 提供的一個基類,通常用來表示數據。

> 補充:[[yii\base\Model]] 被用於普通模型類的父類並與數據表**無關**。[[yii\db\ActiveRecord]] 通常是普通模型類的父類但與數據表有關聯(譯者注:[[yii\db\ActiveRecord]] 類其實也是繼承自 [[yii\base\Model]],增加了數據庫處理)。

`EntryForm` 類包含 `name` 和 `email` 兩個公共成員,用來儲存用戶輸入的數據。它還包含一個名為 `rules()` 的方法,用來返回數據驗證規則的集合。上麵聲明的驗證規則表示:

* `name` 和 `email` 值都是必須的
* `mail` 的值必須滿足 email 地址驗證

如果你有一個從用戶那搜集數據的 `EntryForm` 對象,你可以調用它的 [[yii\base\Model::validate()|validate()]] 方法觸發數據驗證。如果有數據驗證失敗,將把 [[yii\base\Model::hasErrors|hasErrors]] 屬性設為 ture,想要知道具體發生什麼錯誤就調用 [[yii\base\Model::getErrors|getErrors]]。
<?php
$model = new EntryForm();
$model->name = 'Qiang';
$model->email = 'bad';
if ($model->validate()) {
    // 驗證成功!
} else {
    // 失敗!
    // 使用 $model->getErrors() 獲取錯誤詳情
}

創建操作 ​

下麵你得在 `site` 控製器中創建一個 `entry` 操作用於新建的模型。操作的創建和使用已經在[說一聲你好](start-hello.md)小節中解釋了。
<?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 收到的數據

            // 做些有意義的事 ...

            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()]] 去確保用戶提交的是有效數據。

> 補充:表達式 `Yii::$app` 代表[應用]實例,它是一個全局可訪問的單例。同時它也是一個[服務定位器],能提供 `request`,`response`,`db` 等等特定功能的組件。在上麵的代碼裡就是使用 `request` 組件來訪問應用實例收到的 `$_POST` 數據。

用戶提交表單後,操作將會渲染一個名為 `entry-confirm` 的視圖去確認用戶輸入的數據。如果冇填表單就提交,或數據包含錯誤(譯者:如 email 格式不對),`entry` 視圖將會渲染輸出,連同表單一起輸出的還有驗證錯誤的詳細信息。

> 注意:在這個簡單例子裡我們隻是呈現了有效數據的確認頁麵。實踐中你應該考慮使用 [[yii\web\Controller::refresh()|refresh()]] 或 [[yii\web\Controller::redirect()|redirect()]] 去避免[表單重複提交問題](http://en.wikipedia.org/wiki/Post/Redirect/Get)。

創建視圖 ​

最後創建兩個視圖文件 `entry-confirm` 和 `entry`。他們會被剛才創建的 `entry` 操作渲染。

`entry-confirm` 視圖簡單地顯示提交的 name 和 email 數據。視圖文件保存在 `views/site/entry-confirm.php`。
<?php
use yii\helpers\Html;
?>
<p>You have entered the following information:</p>

<ul>
    <li><label>Name</label>: <?= Html::encode($model->name) ?></li>
    <li><label>Email</label>: <?= Html::encode($model->email) ?></li>
</ul>
`entry` 視圖顯示一個 HTML 表單。視圖文件保存在 `views/site/entry.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('Submit', ['class' => 'btn btn-primary']) ?>
    </div>
<?php ActiveForm::end(); ?>
視圖使用了一個功能強大的[小部件](structure-widgets.md) [[yii\widgets\ActiveForm|ActiveForm]] 去生成 HTML 表單。其中的 `begin()` 和 `end()` 分彆用來渲染表單的開始和關閉標簽。在這兩個方法之間使用了 [[yii\widgets\ActiveForm::field()|field()]] 方法去創建輸入框。第一個輸入框用於 “name”,第二個輸入框用於 “email”。之後使用 [[yii\helpers\Html::submitButton()]] 方法生成提交按鈕。

嘗試下 ​

用瀏覽器訪問下麵的 URL 看它能否工作:
http://hostname/index.php?r=site/entry
你會看到一個包含兩個輸入框的表單的頁麵。每個輸入框的前麵都有一個標簽指明應該輸入的數據類型。如果什麼都不填就點擊提交按鈕,或填入格式不正確的 email 地址,將會看到在對應的輸入框下顯示錯誤信息。
[驗證錯誤的表單]
輸入有效的 name 和 email 信息並提交後,將會看到一個顯示你所提交數據的確認頁麵。
[輸入數據的確認頁]

### 效果說明 ​

你可能會好奇 HTML 表單暗地裡是如何工作的呢,看起來它可以為每個輸入框顯示文字標簽,而當你冇輸入正確的信息時又不需要刷新頁麵就能給出錯誤提示,似乎有些神奇。

是的,其實數據首先由客戶端 JavaScript 腳本驗證,然後才會提交給服務器通過 PHP 驗證。[[yii\widgets\ActiveForm]] 足夠智能到把你在 `EntryForm` 模型中聲明的驗證規則轉化成客戶端 JavaScript 腳本去執行驗證。如果用戶瀏覽器禁用了 JavaScript, 服務器端仍然會像 `actionEntry()` 方法裡這樣驗證一遍數據。這保證了任何情況下用戶提交的數據都是有效的。

> 警告:客戶端驗證是提高用戶體驗的手段。無論它是否正常啟用,服務端驗證則都是必須的,請不要忽略它。

輸入框的文字標簽是 `field()` 方法生成的,內容就是模型中該數據的屬性名。例如模型中的 `name` 屬性生成的標簽就是 `Name`。

你可以在視圖中自定義標簽:
<?= $form->field($model, 'name')->label('自定義 Name') ?>
<?= $form->field($model, 'email')->label('自定義 Email') ?>
> 補充:Yii 提供了相當多類似的小部件去幫你生成複雜且動態的視圖。在後麵你還會了解到自己寫小部件是多麼簡單。你可能會把自己的很多視圖代碼轉化成小部件以提高重用,加快開發效率。

總結 

本章節指南中你接觸了 MVC 設計模式的每個部分。學到了如何創建一個模型代表用戶數據並驗證它的有效性。

你還學到了如何從用戶那獲取數據並在瀏覽器上回顯給用戶。這本來是開發應用的過程中比較耗時的任務,好在 Yii 提供了強大的小部件讓它變得如此簡單。

下一章你將學習如何使用數據庫,幾乎每個應用都需要數據庫。