View on GitHub

yii2-cookbook-chinese

Yii Application Development Cookbook(Third Edition)中文翻译

Tabular输入

在本小节中,我们将会想你展示如何使用一个模型保存和验证相关的模型。有时候你需要在一个表单中处理多个相同种类的模型。

例如,我们有竞赛和为竞赛准备的奖牌。任何一个竞赛可能包含没有限制个的奖牌。所以,我们需要能够创建有多个奖牌的竞赛,进行验证,展示错误,保存主模型(竞赛模型)和所有相关模型(多个奖牌模型)到数据库。

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 使用如下命令为竞赛和奖牌表创建migrations:
./yii migrate/create create_table_contest_and_prize_table

更新刚刚创建的migrations的方法up()down()

public function up()
{
    $tableOptions = null;
    if ($this->db->driverName === 'mysql') {
        $tableOptions = 'CHARACTER SET utf8 COLLATE
utf8_general_ci ENGINE=InnoDB';
    }
    $this->createTable('', [
        'id' => Schema::TYPE_PK,
        'name' => Schema::TYPE_STRING . ' NOT NULL',
    ], $tableOptions);
    $this->createTable('', [
        'id' => Schema::TYPE_PK,
        'name' => Schema::TYPE_STRING,
        'amount' => Schema::TYPE_INTEGER,
    ], $tableOptions);
    $this->createTable('', [
        'contest_id' => Schema::TYPE_INTEGER,
        'prize_id' => Schema::TYPE_INTEGER,
    ], $tableOptions);
    $this->addForeignKey('fk_contest_prize_assn_contest_id', '', 'contest_id', '', 'id');
    $this->addForeignKey('fk_contest_prize_assn_prize_id', '', 'prize_id', '', 'id');
}

public function down()
{
    $this->dropForeignKey('fk_contest_prize_assn_contest_id', '');
    $this->dropForeignKey('fk_contest_prize_assn_prize_id', '');
    $this->dropTable('');
    $this->dropTable('');
    $this->dropTable('');
}
  1. 然后,使用如下命令进行安装:
./yii migrate/up
  1. 使用Gii创建竞赛、奖牌和ContestPrizeAssn模型。

如何做…

  1. 创建@app/controllers/ContestController.php
<?php
namespace app\controllers;
use app\models\Contest;
use app\models\ContestPrizeAssn;
use app\models\Prize;
use Yii;
use yii\base\Model;
use yii\helpers\VarDumper;
use yii\web\Controller;
class ContestController extends Controller
{
    public function actionCreate()
    {
        $contestName = 'Happy New Year';
        $firstPrize = new Prize();
        $firstPrize->name = 'Iphone 6s';
        $firstPrize->amount = 4;
        $secondPrize = new Prize();
        $secondPrize->name = 'Sony Playstation 4';
        $secondPrize->amount = 2;
        $contest = new Contest();
        $contest->name = $contestName;
        $prizes = [$firstPrize, $secondPrize];
        if ($contest->validate() &&
            Model::validateMultiple($prizes)) {
            $contest->save(false);
            foreach ($prizes as $prize) {
                $prize->save(false);
                $contestPrizeAssn = new ContestPrizeAssn();
                $contestPrizeAssn->prize_id = $prize->id;
                $contestPrizeAssn->contest_id = $contest>id;
                $contestPrizeAssn->save(false);
            }
            return $this->renderContent(
                'All prizes have been successfully saved!'
            );
        } else {
            return $this->renderContent(
                VarDumper::dumpAsString($contest->getErrors())
            );
        }
    }
    public function actionUpdate()
    {
        $prizes = Prize::find()->all();
        if (Model::loadMultiple($prizes,
                Yii::$app->request->post()) &&
            Model::validateMultiple($prizes)) {
            foreach ($prizes as $prize) {
                $prize->save(false);
            }
            return $this->renderContent(
                'All prizes have been successfully saved!'
            );
        }
        return $this->render('update', ['prizes' => $prizes]);
    }
}
  1. 创建@app/views/contest/update.php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
$form = ActiveForm::begin();
foreach ($prizes as $i => $prize) {
    echo $form->field($prize, "[$i]amount")->label($prize->name);
}
echo Html::submitButton('submit' , ['class' => 'btn btn-success']);
ActiveForm::end();

工作原理…

以下信息展示了如何应用tabular到Yii中。

contest/update动作中,我们会展示所有的奖牌并同时进行编辑。我们使用了两个特殊的Yii方法:

因为我们已经使用了vilidateMultiple()验证了所有的模型,我们给save()传递false参数来避免再次校验。

首先,访问/index.php?r=contest/create页面,访问过以后,这个页面将会验证并创建带有两个奖牌的’Happy New Year’,并将奖牌传递给当前竞赛模型。你应该注意到只有当合法时,我们才会保存竞赛模型和奖牌:

它是通过如下条件提供的:

if ($contest->validate() && Model::validateMultiple($prizes)) { ...}

访问/index.php?r=contest/update

@app/views/contest/update.php中,对于每一个奖牌,我们渲染了一个名称和一个输入框。我们必须给每一个输入框添加一个序号,这样Model::loadMultiple()才能识别出每个输入框对应着哪个模型。

综上,这个方法被用于搜集tabular输入数据:你需要在一个视图的表单中,同时搜集一个父模型和多个相关模型的数据。

参考

欲了解更多信息,参考如下地址: