@newbie360 You can use BulkAction::
use Filament\Tables\Actions\DeleteBulkAction;
DeleteBulkAction::make()
->after(function (Collection $records) {
YourModel::reorderColumn();
}),
Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.
Imagine a Filament table, there has a checkbox in front of each record, so we can delete multiple records, and i want reorder the order_column after record deleted
delete model
deleted: update `order_column` statement
delete model
deleted: update `order_column` statement
delete model
deleted: update `order_column` statement
to implement above code is easy, just in the deleted event, do something like this
update `table` set `order_column` = case when id = '10' then 9 when id = '11' then 10 end, where `order_column` > $deletedModel->order_column
but Laravel has any method to run code after all deleted event finished? If Yes, so i can
delete model
delete model
delete model
after all deleted: update `order_column` statement
Finally, problem solved, thx @tisuchi pointing me to the right direction
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class Tag extends Model
{
protected static array $queued = [];
public function tagCategory(): BelongsTo
{
return $this->belongsTo(TagCategory::class);
}
protected static function booted(): void
{
static::deleted(function (Tag $tag) {
$tagCategoryId = $tag->tag_category_id;
$orderColumn = $tag->order_column;
if (array_key_exists($tagCategoryId, static::$queued)) {
static::$queued[$tagCategoryId] = min(static::$queued[$tagCategoryId], $orderColumn);
} else {
static::$queued[$tagCategoryId] = $orderColumn;
}
dispatch(function () {
if (empty(static::$queued)) {
return; // Make the dispatch run once only.
}
self::reorderColumn(collect(static::$queued));
static::$queued = [];
})->afterResponse();
});
}
public static function reorderColumn(Collection $queued): void
{
$queued->each(function (int $minOrder, int $tagCategoryId): void {
// Use raw statement because builder not support `common table expression (CTE)`.
DB::statement('
WITH cte AS (
SELECT
id,
ROW_NUMBER() OVER (ORDER BY order_column) + ? AS new_order
FROM tags
WHERE tag_category_id = ?
AND order_column > ?
ORDER BY order_column
)
UPDATE tags
INNER JOIN cte ON tags.id = cte.id
SET tags.order_column = cte.new_order;
', [
$minOrder - 1,
$tagCategoryId,
$minOrder,
]);
});
}
}
if bulk delete in Filament table, the DB statement will only update the highlighted records because there use AND order_column > $minOrder
| id | tag_category_id | order_column |
| --- | --------------- | ------------ |
| ... | 1 | 1 |
| ... | 1 | 2 |
| ... | 1 | ... |
| 55 | 1 | 55 |
| 56 | 1 | 56 | bulk delete ($minOrder)
| 57 | 1 | 57 | bulk delete
+ | 58 | 1 | 58 |
| ... | 2 | 1 |
| ... | 2 | 2 |
| ... | 2 | ... |
| 500 | 2 | 97 |
| 501 | 2 | 98 | bulk delete ($minOrder)
| 502 | 2 | 99 | bulk delete
+ | 503 | 2 | 100 |
+ | 504 | 2 | 101 |
so after the records deleted
| id | tag_category_id | order_column |
| --- | --------------- | ------------ |
| ... | 1 | 1 |
| ... | 1 | 2 |
| ... | 1 | ... |
| 55 | 1 | 55 |
+ | 58 | 1 | 56 |
| ... | 2 | 1 |
| ... | 2 | 2 |
| ... | 2 | ... |
| 500 | 2 | 97 |
+ | 503 | 2 | 98 |
+ | 504 | 2 | 99 |
happy coding =)
Please or to participate in this conversation.