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

sparmin's avatar

Strange behaviour of refreshing form components after action

The context is not super necessary but here is what it does:

Inside the form of the GamesResource, I have this status area. If the game is not running (!$game->is_running), the message says accordingly "Das Spiel ist noch nicht gestartet." and the button to start the game is visible. Now once I press this button, all the necessary flags and attributes are set ($game->startGame()) and the status bar refreshes on its own, displaying now the current round by saying "Aktuelle Runde: 1". Furthermore, the startGame button is not visible anymore, but instead the button for the next round.

Now the strange thing happens. Both actions are basically doing the same thing, applying changes to the $game object and saving it. But unlike the startGame action, the startNextRound action does NOT trigger a refresh of the status display. So after clicking the button the message still says "Aktuelle Runde: 1" and only after refreshing the page it says correctly "Aktuelle Runde: 2".

Why is this behaviour happening?

Here is the relevant code of the GamesResource:

Section::make('Spielsteuerung')
                    ->schema([
                        Forms\Components\Placeholder::make('status')
                            ->label('Aktueller Status')
                            ->content(function ($record) {
                                if (!$record->is_running && !$record->current_round) {
                                    return 'Das Spiel ist noch nicht gestartet.';
                                } elseif ($record->isGameFinished()) {
                                    return 'Spiel beendet.';
                                } else {
                                    return 'Aktuelle Runde: ' . $record->currentRound->sort;
                                }
                            }),
                        Forms\Components\Actions::make([
                            Forms\Components\Actions\Action::make('startGame')
                                ->label('Spiel starten')
                                ->button()
                                ->visible(fn($record) => !$record->is_running)
                                ->action(function (Game $record) {
                                    $record->startGame();
                                }),
                            Forms\Components\Actions\Action::make('startNextRound')
                                ->label('Nächste Runde')
                                ->button()
                                ->visible(fn($record) => $record->is_running && !$record->isGameFinished() && !$record->isLastRound())
                                ->action(function (Game $record) {
                                    $record->startNextRound();
                                }),
                        ]),
                    ])

This is the Game model that has relations to the Round model. Here are the relevant functions inside the Game class:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class Game extends Model
{
    use HasFactory;

    protected $fillable = [
        'label',
        'hash',
        'user_id',
        'is_preset',
        'is_active',
        'budget',
        'profit',
        'is_running',
        'current_round'
    ];

    public function isGameFinished()
    {
        return $this->current_round // check if current round is set
            && $this->rounds()->count() === $this->currentRound->sort // check if current round is the last round
            && $this->teams->every(function ($team) { // check if every team has made a decision
                return $team->decisions()->where('round_id', $this->current_round)->exists();
            });
    }

    public function startGame() {
        $this->is_running = true;
        $this->current_round = $this->rounds()->orderBy('sort')->first()->id;
        $this->save();
    }

    public function startNextRound() {
        $currentRoundSort = $this->rounds()->where('id', $this->current_round)->first()->sort;
        $nextRound = $this->rounds()->where('sort', $currentRoundSort + 1)->first();
        $this->current_round = $nextRound->id;
        $this->save();
    }

    public function isLastRound() {
        return $this->currentRound->sort === $this->rounds()->count();
    }

    public function rounds(): HasMany
    {
        return $this->hasMany(Round::class);
    }

    public function teams(): HasMany
    {
        return $this->hasMany(Team::class);
    }

    public function decisions(): HasMany
    {
        return $this->hasMany(Decision::class);
    }

    public function currentRound(): HasOne {
        return $this->hasOne(Round::class, 'id', 'current_round');
    }
}
0 likes
0 replies

Please or to participate in this conversation.