Yii2 - 更新包含子记录的记录

时间:2018-06-07 16:22:01

标签: yii2

我有一个允许用户添加许多子记录的表单,在我的情况下,他们被称为" Items"。更新主记录时,用户可以添加,编辑或删除子记录。一切正常,但我正在寻找更好的方法来做到这一点。

目前,在我的Update操作中,我首先删除任何现有的子记录。然后我保存表格帖子中的所有子记录。

public function actionUpdate($id)
{
    $model = $this->findModel($id);

    if ($model->load(Yii::$app->request->post()) && $model->save()) {
        // first delete all existing child records
        Item::deleteAll(['parent_id' => $model->id]);

        // get the new set of posted Items
        $items = Yii::$app->request->post('Item');

        if (!empty($items) && is_array($items)) {
            // save each Item
            foreach ($items as $index => $values) {
                $item = new Item();
                $item->attributes = $values;
                $item->parent_id = $model->id;
                $item->save();
            }
        }

        return $this->redirect(['view', 'id' => $model->id]);
    }

    return $this->render('update', [
        'model' => $model,
    ]);
}

表单视图:

<form method="post" action="">
    <?php foreach ($model->items as $index => $item): ?>
        <?php echo Html::activeTextInput($item, "[$index]name"); ?>

        <!-- Example output -->
        <!-- <input id="item-0-name" name="Item[0][name]" value="Test" type="text"> -->

        <a href="#">Remove this Item</a>
    <?php endforeach; ?>

    <button type="submit">Submit</button>
</form>

<a href="#">Add a new Item</a>

在上面$model->items指的是父模型中的关系:

public function getItems()
{
    return $this->hasMany(Item::className(), ['parent_id' => 'id']);
}

当用户点击&#34;添加新商品&#34;它只是使用JavaScript来克隆最后一项,并用下一个值替换它的索引。

通常,用户不会更改任何子记录。因此,在这种情况下删除和重新添加子记录的过程毫无意义。

我想知道的是,有没有办法可以智能地处理这个问题?例如:

  • 仅删除子项记录(如果POST项目数组中不存在)
  • 仅编辑子记录(如果它们与数据库中的记录不同)
  • 仅添加数据库中当前不存在的新子记录
  • 否则保留所有内容

1 个答案:

答案 0 :(得分:2)

您可以使用indexBy()按ID标识与索引相关项目的关系:

public function getItems() {
    return $this->hasMany(Item::class, [/*...*/])->indexBy('id');
}

然后您可以检查具有此ID的记录是否已存在并执行更新/删除/创建操作:

// get the new set of posted Items
$items = Yii::$app->request->post('Item');
$existing = $model->items;

if (!empty($items) && is_array($items)) {
    // save each Item
    foreach ($items as $index => $values) {
        if (!isset($existing[$index])) {
            // create new item
            $item = new Item();
            $item->attributes = $values;
            $item->parent_id = $model->id;
            $item->save();
        } else {
            // update existing
            $existing[$index]->attributes = $values;
            $existing[$index]->save();
            // remove from $existing array as already processed
            unset($existing[$index]);
        }
    }

    // right now $existing has only existing and not updated items - it means
    // that they're not available in POST data so we should remove it
    foreach ($existing as $item) {
        $item->delete();
    }
}