Tabular输入

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

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

准备

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

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

  1. public function up()
  2. {
  3. $tableOptions = null;
  4. if ($this->db->driverName === 'mysql') {
  5. $tableOptions = 'CHARACTER SET utf8 COLLATE
  6. utf8_general_ci ENGINE=InnoDB';
  7. }
  8. $this->createTable('{{%contest}}', [
  9. 'id' => Schema::TYPE_PK,
  10. 'name' => Schema::TYPE_STRING . ' NOT NULL',
  11. ], $tableOptions);
  12. $this->createTable('{{%prize}}', [
  13. 'id' => Schema::TYPE_PK,
  14. 'name' => Schema::TYPE_STRING,
  15. 'amount' => Schema::TYPE_INTEGER,
  16. ], $tableOptions);
  17. $this->createTable('{{%contest_prize_assn}}', [
  18. 'contest_id' => Schema::TYPE_INTEGER,
  19. 'prize_id' => Schema::TYPE_INTEGER,
  20. ], $tableOptions);
  21. $this->addForeignKey('fk_contest_prize_assn_contest_id', '{{%contest_prize_assn}}', 'contest_id', '{{%contest}}', 'id');
  22. $this->addForeignKey('fk_contest_prize_assn_prize_id', '{{%contest_prize_assn}}', 'prize_id', '{{%prize}}', 'id');
  23. }
  24. public function down()
  25. {
  26. $this->dropForeignKey('fk_contest_prize_assn_contest_id', '{{%contest_prize_assn}}');
  27. $this->dropForeignKey('fk_contest_prize_assn_prize_id', '{{%contest_prize_assn}}');
  28. $this->dropTable('{{%contest_prize_assn}}');
  29. $this->dropTable('{{%prize}}');
  30. $this->dropTable('{{%contest}}');
  31. }
  1. 然后,使用如下命令进行安装:
  1. ./yii migrate/up
  1. 使用Gii创建竞赛、奖牌和ContestPrizeAssn模型。

如何做…

  1. 创建@app/controllers/ContestController.php
  1. <?php
  2. namespace app\controllers;
  3. use app\models\Contest;
  4. use app\models\ContestPrizeAssn;
  5. use app\models\Prize;
  6. use Yii;
  7. use yii\base\Model;
  8. use yii\helpers\VarDumper;
  9. use yii\web\Controller;
  10. class ContestController extends Controller
  11. {
  12. public function actionCreate()
  13. {
  14. $contestName = 'Happy New Year';
  15. $firstPrize = new Prize();
  16. $firstPrize->name = 'Iphone 6s';
  17. $firstPrize->amount = 4;
  18. $secondPrize = new Prize();
  19. $secondPrize->name = 'Sony Playstation 4';
  20. $secondPrize->amount = 2;
  21. $contest = new Contest();
  22. $contest->name = $contestName;
  23. $prizes = [$firstPrize, $secondPrize];
  24. if ($contest->validate() &&
  25. Model::validateMultiple($prizes)) {
  26. $contest->save(false);
  27. foreach ($prizes as $prize) {
  28. $prize->save(false);
  29. $contestPrizeAssn = new ContestPrizeAssn();
  30. $contestPrizeAssn->prize_id = $prize->id;
  31. $contestPrizeAssn->contest_id = $contest>id;
  32. $contestPrizeAssn->save(false);
  33. }
  34. return $this->renderContent(
  35. 'All prizes have been successfully saved!'
  36. );
  37. } else {
  38. return $this->renderContent(
  39. VarDumper::dumpAsString($contest->getErrors())
  40. );
  41. }
  42. }
  43. public function actionUpdate()
  44. {
  45. $prizes = Prize::find()->all();
  46. if (Model::loadMultiple($prizes,
  47. Yii::$app->request->post()) &&
  48. Model::validateMultiple($prizes)) {
  49. foreach ($prizes as $prize) {
  50. $prize->save(false);
  51. }
  52. return $this->renderContent(
  53. 'All prizes have been successfully saved!'
  54. );
  55. }
  56. return $this->render('update', ['prizes' => $prizes]);
  57. }
  58. }
  1. 创建@app/views/contest/update.php
  1. <?php
  2. use yii\helpers\Html;
  3. use yii\widgets\ActiveForm;
  4. $form = ActiveForm::begin();
  5. foreach ($prizes as $i => $prize) {
  6. echo $form->field($prize, "[$i]amount")->label($prize->name);
  7. }
  8. echo Html::submitButton('submit' , ['class' => 'btn btn-success']);
  9. ActiveForm::end();

工作原理…

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

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

  • Model::loadMultiple():这个方法使用终端用户的数据填充了多个模型
  • Model::vilidateMultiple():这个方法同时验证了多个模型

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

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

Tabular输入 - 图1

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

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

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

Tabular输入 - 图2

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

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

参考

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