<p>You're setting the field value and saving the matrix block once for every row in your table, you only need to do that once. The actual problem is that you're merging a new array into <code>$table</code> for every existing row, so essentially you're duplicating every row. However, that error is obscured by all the procedural code.</p>
<p>All you want is to get the same table, but with some values replaced. This is a simple <a href="https://www.php.net/manual/en/function.array-map.php" rel="nofollow noreferrer">map operation</a>.</p>
<p>Something like this should work better:</p>
<pre class="lang-php prettyprint-override"><code>$blocks = $entry-&gt;matrixField-&gt;all();
foreach ($blocks as $block) {
    $newTable = array_map(
        fn(array $row) =&gt; [
            'category' =&gt; $row['category'] !== 'A' ? $row['category'] : 'B',
            'event' =&gt; $row['event'],
        ],
        $block-&gt;table,
    );
    $block-&gt;setFieldValue('table', $newTable);
    Craft::$app-&gt;elements-&gt;saveElement($block);
}
</code></pre>

CC BY-SA 4.0
2024-01-28T01:00:54.653Z
This is great, thank you!
supazu
CC BY-SA 4.0
2024-01-27T17:14:31.397Z
2024-01-27T17:14:31.397Z
MoritzLost
<p>I have a Matrix field, and blocks have a Table field inside of them, with two columns: event and category.</p>
<p>I want to now set anything with category 'A' to category 'B' via a module (listening to <code>Entry::EVENT_BEFORE_SAVE</code>). I've got it updating the value correctly, but it adds it as a new row, rather than replacing the existing row.</p>
<p>I think I might need to use <code>unset</code>, to remove the row that matches, but I'm struggling to get that part working. Does anyone have any thoughts?</p>
<pre><code>$blocks = $entry-&gt;matrixField-&gt;all();
foreach ($blocks as $block) {
    $table = $block-&gt;table;
    foreach ($table as $row) {
        $event = $row['event'];
        $category = $row['category'];
        if ($category === 'A') {
            $category = 'B';
        }
        $updatedTable = [[
            'event' =&gt; $event,
            'category' =&gt; $category,
        ]];
        $block-&gt;setFieldValue('table', array_merge($table ?? [], $updatedTable));
        Craft::$app-&gt;elements-&gt;saveElement($block);
    }
}
</code></pre>

<matrix><modules><table-field>
Replace the value of a table cell (inside a Matrix field)
# Replace the value of a table cell (inside a Matrix field)

(Asked by: username_0 on 2024-01-27)

I have a Matrix field, and blocks have a Table field inside of them, with two columns: event and category.
I want to now set anything with category 'A' to category 'B' via a module (listening to Entry::EVENT_BEFORE_SAVE). I've got it updating the value correctly, but it adds it as a new row, rather than replacing the existing row.
I think I might need to use unset, to remove the row that matches, but I'm struggling to get that part working. Does anyone have any thoughts?
$blocks = $entry->matrixField->all();
foreach ($blocks as $block) {
    $table = $block->table;
    foreach ($table as $row) {
        $event = $row['event'];
        $category = $row['category'];
        if ($category === 'A') {
            $category = 'B';
        }
        $updatedTable = [[
            'event' => $event,
            'category' => $category,
        ]];
        $block->setFieldValue('table', array_merge($table ?? [], $updatedTable));
        Craft::$app->elements->saveElement($block);
    }
}

**Tags:** matrix, modules, table-field


---

## 1 answers

### Answer by username_1 on 2024-01-27. Score: 2 | Accepted answer

You're setting the field value and saving the matrix block once for every row in your table, you only need to do that once. The actual problem is that you're merging a new array into $table for every existing row, so essentially you're duplicating every row. However, that error is obscured by all the procedural code.
All you want is to get the same table, but with some values replaced. This is a simple map operation.
Something like this should work better:
$blocks = $entry->matrixField->all();
foreach ($blocks as $block) {
    $newTable = array_map(
        fn(array $row) => [
            'category' => $row['category'] !== 'A' ? $row['category'] : 'B',
            'event' => $row['event'],
        ],
        $block->table,
    );
    $block->setFieldValue('table', $newTable);
    Craft::$app->elements->saveElement($block);
}

> **Comments:**
> **username_0**: This is great, thank you!  

---

