Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

newbie360's avatar

Run code after all deleted event

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
0 likes
6 replies
tisuchi's avatar

@newbie360 You can use BulkAction::


use Filament\Tables\Actions\DeleteBulkAction;

DeleteBulkAction::make()
    ->after(function (Collection $records) {
        YourModel::reorderColumn(); 
    }),
tisuchi's avatar

@newbie360 Then you can try this:

in your model observer (YourModelObserver):

use Illuminate\Support\Facades\Queue;

class YourModelObserver
{
    protected static bool $queued = false;

    public function deleted(YourModel $model): void
    {
        if (! static::$queued) {
            static::$queued = true;

            Queue::afterResponse(function () {
                YourModel::reorderColumn();
                static::$queued = false;
            });
        }
    }
}

After that Add the reorderColumn() method to your model:

public static function reorderColumn(): void
{
    $ordered = self::orderBy('order_column')->get();

    foreach ($ordered as $index => $item) {
        $item->updateQuietly(['order_column' => $index + 1]);
    }
}
newbie360's avatar

@tisuchi I guess your code should work, but i need some time to make changes to meet my use case =) i will report back soon

tags table

| id | tag_category_id | name | order_column |
| -- | --------------- | ---- | ------------ |
| 1  |       1         | aa   |      1       |
| 2  |       1         | bb   |      2       |
| 3  |       2         | xx   |      1       |
| 4  |       2         | yy   |      2       |
newbie360's avatar

I fall in a trap, actually i want use once() helper to reduce the number of query when use factory

in all my Tests is passed, BUT after read again the above creating event, go to the Web UI create a new tag for the tag_category_id 1, the order_column always is 1, because the //Marker

        // TODO: reduce the number of query when use factory
        static::creating(function (Tag $tag) {
            $maxOrder = self::getMaxOrderBy($tag->tag_category_id);

            $tag->order_column = $maxOrder + 1;
        });

    /**
     * Get the max value of `order_column` by the `tag_category_id`.
     */
    public static function getMaxOrderBy(int $tagCategoryId): int
    {
        $maxOrder = self::query()
            ->where('tag_category_id', $tagCategoryId)
            ->max('order_column');

        return $maxOrder ?? 0;
    }

@tisuchi Call to undefined method Illuminate\Queue\DatabaseQueue::afterResponse()

            Queue::afterResponse(function () {
                YourModel::reorderColumn();
                static::$queued = false;
            });

tags table (bulk delete)

| id | tag_category_id | name | order_column |
| -- | --------------- | ---- | ------------ |
| 1  |       1         | aa   |      1       | delete
| 2  |       1         | bb   |      2       |
| 3  |       2         | xx   |      1       | delete
| 4  |       2         | yy   |      2       | delete
| 5  |       2         | zz   |      3       |

so far i working on this

class Tag extends Model
{
    // use array instead of bool
    // because possible delete different `tag_category_id` in the same request,
    protected static array $queued = [];

    protected static function booted(): void
    {
        static::deleted(function (Tag $tag) {
            info('tag_category_id ' . $tag->tag_category_id);

            if (! in_array($tag->tag_category_id, static::$queued)) {
                static::$queued[] = $tag->tag_category_id;

                info('new array', static::$queued);

                dispatch(function () {
                    self::reorderColumnBy(static::$queued);

                    static::$queued = [];
                })->afterResponse();
            }
        });
    }

    public static function reorderColumnBy(array $queued): void
    {
        info('reorder tag_category_id', $queued);
    }

laravel.log , added line break for easy understand the behavior

local.INFO: tag_category_id 1  
local.INFO: new array [1] 

local.INFO: tag_category_id 2  
local.INFO: new array [1,2] 

local.INFO: tag_category_id 2  

local.INFO: reorder tag_category_id [1,2] 
local.INFO: reorder tag_category_id

it works, but only the problem is dispatch fired two times, any idea to fire once only?

newbie360's avatar
newbie360
OP
Best Answer
Level 24

Finally, problem solved, thx @tisuchi pointing me to the right direction

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.