sebdesign/laravel-state-machine

Issue defining callbacks in state-machine.php

Closed this issue · 3 comments

I have a laravel 9 project, with php 8.1
laravel-state-machine version 3.3.0

These don't work

'callbacks' => [
	'after' => [
		'after_registrar' => [
			'on' => 'enviar_documentacion',
			'do' => [\App\Actions\AfterTramiteTransition::class, 'run'], 
			'args' => ['event', 'object'],
		],
	],
],
'callbacks' => [
	'after' => [
		'after_enviar_documentacion' => [
			'on' => 'enviar_documentacion',
			'do' => '\App\Actions\AfterTramiteTransition@run',
			'args' => ['event', 'object'],
		],
	],
],

The error I get is :

  TypeError

  SM\Callback\Callback::filterCallable(): Return value must be of type callable, string returned

  at vendor/winzou/state-machine/src/SM/Callback/Callback.php:142

or Return value must be of type callable, array returned if I used the first one.

Digging a bit into the winzou library I found SM\Callback\CallbackInterface
That's an invokable class.

If I do this it works

'callbacks' => [
	'after' => [
		'after_enviar_documentacion' => [
			'on' => 'enviar_documentacion',
			'do' => new \App\Actions\AfterTramiteTransition(),
			'args' => ['event', 'object'],
		],
	],
],

But the problem is with Laravel with that approach. php artisan config:cahe will fail because it can't serialize the config files.

Since that class is an invokable I tried 'do' => \App\Actions\AfterTramiteTransition::class, but no luck, same error

I don't know what I'm doing wrong or what changed but I have another project in Laravel 8, with laravel-state-machine 3.2.1 and I have no issues using 'do' => [\App\MyClass:class, 'method'] to define callbacks.

Hello,

That's quite strange. Can you tell me the version of the "winzou/state-machine" that is installed?

composer show | grep winzou/state-machine

I figured out what's happening.

The run method on the App\Actions\AfterTramiteTransition class is not a static method, so PHP cannot call it statically.
This package tries to resolve the instance of the App\Actions\AfterTramiteTransition from the container, in order to call it normally. Since the class is not registered in the Laravel container, that doesn't work.

You need to register App\Actions\AfterTramiteTransition in your AppServiceProvider (or any other service provider) like this:

public function register()
{
    $this->bind(\App\Actions\AfterTramiteTransition::class);
}

or like this:

public array $bindings = [
    \App\Actions\AfterTramiteTransition => \App\Actions\AfterTramiteTransition::class,
];

or like this:

public array $bindings = [
    \App\Actions\AfterTramiteTransition => null,
];

Thanks you !
That was the issue. Either defining the the method as static or manually registering the class in Laravel's container.