文字
分享

收集列表输入

收集列表输入

有时你需要在一个表单中以单一的形式处理多个模型。例如,有多个设置,每个设置存储为一个 name-value,并通过 Setting 活动记录模型来表示。 这种形式也常被称为“列表输入”。与此相反,处理不同模型的不同类型,在多模型同时输入章节中介绍。

下面展示了如何在 Yii 中收集列表输入。

在三种不同的情况下,所需处理的略有不同:

  • 从数据库中更新一组固定的记录
  • 创建一个动态的新记录集
  • 更新、创建和删除一页记录

与之前介绍的单一模型表单相反,我们现在用的是一个数组类的模型。这个数组将每个模型传递到视图并以一种类似于表格的方式来显示表单字段。 我们使用 yii\base\Model 助手类方法来一次性地加载和验证多模型数据:

  • yii\base\Model::loadMultiple() 将数据加载到一个数组中。
  • yii\base\Model::validateMultiple() 验证一系列模型。

更新一组固定的记录

让我们从控制器的动作开始:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: inherit; padding: 0px; color: inherit; border-radius: 0px; white-space: pre-wrap; background-color: transparent;"><span style="box-sizing: border-box;"><?php</span>

 

<span style="box-sizing: border-box;">namespace</span> <span style="box-sizing: border-box;">app</span>\<span style="box-sizing: border-box;">controllers</span>;

 

<span style="box-sizing: border-box;">use</span> <span style="box-sizing: border-box;">Yii</span>;

<span style="box-sizing: border-box;">use</span> <span style="box-sizing: border-box;">yii</span>\<span style="box-sizing: border-box;">base</span>\<span style="box-sizing: border-box;">Model</span>;

<span style="box-sizing: border-box;">use</span> <span style="box-sizing: border-box;">yii</span>\<span style="box-sizing: border-box;">web</span>\<span style="box-sizing: border-box;">Controller</span>;

<span style="box-sizing: border-box;">use</span> <span style="box-sizing: border-box;">app</span>\<span style="box-sizing: border-box;">models</span>\<span style="box-sizing: border-box;">Setting</span>;

 

<span style="box-sizing: border-box;"><span style="box-sizing: border-box;">class</span> <span style="box-sizing: border-box;">SettingsController</span> <span style="box-sizing: border-box;">extends</span> <span style="box-sizing: border-box;">Controller</span></span>{

    <span style="box-sizing: border-box;">// ...</span>

 

    <span style="box-sizing: border-box;">public</span> <span style="box-sizing: border-box;"><span style="box-sizing: border-box;">function</span> <span style="box-sizing: border-box;">actionUpdate</span><span style="box-sizing: border-box;">()</span>

    </span>{

        <span style="box-sizing: border-box;">$settings</span> = Setting::find()->indexBy(<span style="box-sizing: border-box;">'id'</span>)->all();

 

        <span style="box-sizing: border-box;">if</span> (Model::loadMultiple(<span style="box-sizing: border-box;">$settings</span>, Yii::<span style="box-sizing: border-box;">$app</span>->request->post()) && Model::validateMultiple(<span style="box-sizing: border-box;">$settings</span>)) {

            <span style="box-sizing: border-box;">foreach</span> (<span style="box-sizing: border-box;">$settings</span> <span style="box-sizing: border-box;">as</span> <span style="box-sizing: border-box;">$setting</span>) {

                <span style="box-sizing: border-box;">$setting</span>->save(<span style="box-sizing: border-box;">false</span>);

            }

            <span style="box-sizing: border-box;">return</span> <span style="box-sizing: border-box;">$this</span>->redirect(<span style="box-sizing: border-box;">'index'</span>);

        }

 

        <span style="box-sizing: border-box;">return</span> <span style="box-sizing: border-box;">$this</span>->render(<span style="box-sizing: border-box;">'update'</span>, [<span style="box-sizing: border-box;">'settings'</span> => <span style="box-sizing: border-box;">$settings</span>]);

    }

}

</code>

在上面的代码中,当用模型来从数据库获取数据时,我们使用 yii\db\ActiveQuery::indexBy() 来让模型的主键成为一个数组的索引。 其中 yii\base\Model::loadMultiple() 用于接收以 POST 方式提交的表单数据并填充多个模型, yii\base\Model::validateMultiple() 一次验证多个模型。 正如我们之前验证的模型,使用了 validateMultiple(),现在通过传递 false 作为 yii\db\ActiveRecord::save() 的一个参数使其不会重复验证两次。

现在在 update 视图的表单:

1

2

3

4

5

6

7

8

9

10

11

<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: inherit; padding: 0px; color: inherit; border-radius: 0px; white-space: pre-wrap; background-color: transparent;"><span style="box-sizing: border-box;"><?php</span><span style="box-sizing: border-box;">use</span> <span style="box-sizing: border-box;">yii</span>\<span style="box-sizing: border-box;">helpers</span>\<span style="box-sizing: border-box;">Html</span>;

<span style="box-sizing: border-box;">use</span> <span style="box-sizing: border-box;">yii</span>\<span style="box-sizing: border-box;">widgets</span>\<span style="box-sizing: border-box;">ActiveForm</span>;

 

<span style="box-sizing: border-box;">$form</span> = ActiveForm::begin();

 

<span style="box-sizing: border-box;">foreach</span> (<span style="box-sizing: border-box;">$settings</span> <span style="box-sizing: border-box;">as</span> <span style="box-sizing: border-box;">$index</span> => <span style="box-sizing: border-box;">$setting</span>) {

    <span style="box-sizing: border-box;">echo</span> <span style="box-sizing: border-box;">$form</span>->field(<span style="box-sizing: border-box;">$setting</span>, <span style="box-sizing: border-box;">"[$index]value"</span>)->label(<span style="box-sizing: border-box;">$setting</span>->name);

}

 

ActiveForm::end();

</code>

在这里,我们为每个设置渲染了名字和一个带值的输入。重要的是给 input name 增加添加适当的索引, 因为这是由 yii\base\Model::loadMultiple() 来决定以哪些值来填补哪个模型。

创建一组动态的新记录

创造新的记录与修改记录很相似,除部分实例化模型不同之外:

1

2

3

4

5

6

7

8

9

10

<code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: inherit; padding: 0px; color: inherit; border-radius: 0px; white-space: pre-wrap; background-color: transparent;"><span style="box-sizing: border-box;">public</span> <span style="box-sizing: border-box;"><span style="box-sizing: border-box;">function</span> <span style="box-sizing: border-box;">actionCreate</span><span style="box-sizing: border-box;">()</span></span>{

    <span style="box-sizing: border-box;">$count</span> = count(Yii::<span style="box-sizing: border-box;">$app</span>->request->post(<span style="box-sizing: border-box;">'Setting'</span>, []));

    <span style="box-sizing: border-box;">$settings</span> = [<span style="box-sizing: border-box;">new</span> Setting()];

    <span style="box-sizing: border-box;">for</span>(<span style="box-sizing: border-box;">$i</span> = <span style="box-sizing: border-box;">1</span>; <span style="box-sizing: border-box;">$i</span> < <span style="box-sizing: border-box;">$count</span>; <span style="box-sizing: border-box;">$i</span>++) {

        <span style="box-sizing: border-box;">$settings</span>[] = <span style="box-sizing: border-box;">new</span> Setting();

    }

 

    <span style="box-sizing: border-box;">// ...</span>

}

</code>

在这里,我们创建了一个初始的 $settings 数组包含一个默认的模型,所以始终至少有一个文本字段是可见的。 此外,我们为每个可能会收到的输入行添加更多的模型。

在视图中,可以使用 JavaScript 来动态地添加新的输入行。

把更新,创建和删除结合在一个页面上

注意:此章节正在开发中。

还没有内容。

TBD