dcodegroup / laravel-state-machines

State machines for Laravel
1 stars 1 forks source link

[BUG] Error when call setStatus #2

Closed hungnt-dcode closed 8 months ago

hungnt-dcode commented 8 months ago

when i try

$task->setStatus(TaskStateContract::INCOMPLETE)

i see the error:


    "exception": "Exception",
    "file": "/var/www/precision-scaffolding/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php",
    "line": 1929,
    "trace": [
        {
            "file": "/var/www/precision-scaffolding/vendor/dcodegroup/laravel-state-machines/src/HasStates.php",
            "line": 46,
            "function": "__get",
            "class": "Illuminate\\Database\\Eloquent\\Builder",
            "type": "->"
        },
        {
            "file": "/var/www/precision-scaffolding/app/Services/Task/TaskService.php",
            "line": 169,
            "function": "setStatus",
            "class": "App\\Models\\Task\\Task",
            "type": "->"
        },
        {
            "file": "/var/www/precision-scaffolding/app/Http/Controllers/API/Admin/Tasks/AddTaskJobController.php",
            "line": 25,
            "function": "save",
            "class": "App\\Services\\Task\\TaskService",
            "type": "->"
        }]
yohannca commented 8 months ago

@hungnt-dcode It seems like you are calling setStatus() straight from the controller. You need to call implement the state() function. I'm thinking about either creating an interface for it or maybe declare a abstract state function from the HasStatus trait.

Once you have implemented the state function https://github.com/dcodegroup/laravel-state-machines?tab=readme-ov-file#configuring-statuses-on-a-model you need to handle changing state from the state machine classes by calling setStatus().

Your controller should call something like $task->state()->incomplete() and you possibly need to update your State Machine as all methods will throw an exception by default. You want to throw an exception if lets say you don't want tasks to be able to switch back to an incomplete state if they have been completed. But if you want to be able to switch from incomplete to complete then you have to call the setStatus method from the transition function.

Also, if you are trying to set a default state, you can override the $defaultState property on your model.

hungnt-dcode commented 8 months ago

Thank for your response, i think the issue will be solved if #3 be solved. Currently $task->state() will throw Exception, cuz $task->status return null, No where create data for statuses table on source code.

//app/Models/Task/Task.php

public function state()
    {
        return match($this->status->machine_name) {
            TaskStateContract::INCOMPLETE => new IncompleteState($this),
            TaskStateContract::CONFIRMED => new ConfirmedState($this),
            TaskStateContract::COMPLETED => new CompletedState($this),
            'default' => throw new \Exception('Invalid state'),
        };
    }
//vendor/dcodegroup/laravel-state-machines/src/HasStates.php

 public function status(): BelongsTo
    {
        return $this->belongsTo(Status::class);
    }