Yii2-使用子记录更新记录

Yii2-使用子记录更新记录,yii2,Yii2,我有一个表单,允许用户添加许多子记录,在我的例子中,它们被称为“项”。更新主记录时,用户可以添加、编辑或删除子记录。一切都很好,但我正在寻找一个更好的方法来做到这一点 目前,在更新操作中,我首先删除所有现有的子记录。然后我保存表单post中的所有子记录 public function actionUpdate($id) { $model = $this->findModel($id); if ($model->load(Yii::$app->request-&

我有一个表单,允许用户添加许多子记录,在我的例子中,它们被称为“项”。更新主记录时,用户可以添加、编辑或删除子记录。一切都很好,但我正在寻找一个更好的方法来做到这一点

目前,在更新操作中,我首先删除所有现有的子记录。然后我保存表单post中的所有子记录

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>
当用户单击“添加一个新项目”时,它只是使用JavaScript克隆最后一个项目,并用下一个值替换其索引

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

我想知道的是,有没有一种方法可以让我聪明地处理这个问题?例如:

  • 仅当过帐项目数组中不存在子记录时才删除它们
  • 仅当子记录与数据库中的记录不同时才编辑它们
  • 仅添加数据库中当前不存在的新子记录
  • 否则一切都保持原样
您可以通过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();
    }
}

Item
model是否有ID或唯一字段?刚刚更新了我的原始帖子。项目模型具有ID主键。在我的表单中,
以“表格”数组格式生成(从零开始)。
!isset($existing[$index])
不起作用,表单字段使用默认数组索引而不是item
id
字段填充,第一个项目将始终具有索引
0
,即使该项目已经存在且id为
112
,但由于该字段已创建
item-0-name
,它将假定
id
0
@MuhammadOmerAslam您确定吗?我做了一些测试,它工作正常-表单提交中保留了
$index
中的索引。因此,只要表单中的
$index
表示记录的ID,它就应该正常工作。我认为,看到OP中的当前表单字段,它们被填充为
$index
这里不是
表的
ID
?还是我错了?我想你错了,
$this->hasMany(Item::class,[/*…*/])->indexBy('id')
应确保
$model->items
将根据item ID进行索引。Hmm!您正在使用的
indexBy()
将根据给定列对其进行索引,但完全忽略了这一点。
// 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();
    }
}