Action
Actions encapsulate side-effect logic that can be invoked from states. They're useful for handling business logic, API calls, database operations, and other tasks that shouldn't be directly in your state classes.
Creating an Action
Use the Artisan command to create a new action:
php artisan ussd:action ProcessPayment
Action Structure
<?php
namespace App\Ussd\Actions;
use Vendor\LaravelUssd\Support\AbstractAction;
use Vendor\LaravelUssd\Support\Context;
class ProcessPayment extends AbstractAction
{
public function handle(Context $context, string $input): mixed
{
// Your business logic here
$amount = $input;
$account = $context->data['account_number'] ?? null;
// Process payment
$result = $this->paymentService->process($account, $amount);
if ($result->success) {
$context->data['payment_id'] = $result->id;
return ['success' => true, 'message' => 'Payment processed successfully'];
}
return ['success' => false, 'message' => 'Payment failed. Please try again.'];
}
}
Using Actions in States
Actions are called from within your State's next() method to perform business logic. After calling an action, you must return a State class name, not an Action class name.
public function next(Context $context, string $input): ?string
{
$this->setContext($context);
// Call the action to perform business logic
$action = new ProcessPayment();
$result = $action->handle($context, $input);
// IMPORTANT: Return a STATE class name, not an Action class name
if ($result['success']) {
return PaymentSuccessState::class; // ✅ Correct: State class
}
// Handle error case - also return a State
return ErrorState::class; // ✅ Correct: State class
}
Common Mistake: Returning Action Instead of State
⚠️ Important: Never Return Action Class Names
The next() method must return a State class name (string), never an Action class name. Returning an Action will cause a type error:
Machine::resolveState(): Return value must be of type State, Action returned
❌ Incorrect - Returning Action Class
public function next(Context $context, string $input): ?string
{
$this->setContext($context);
// ❌ WRONG: Returning an Action class name
return ProcessPayment::class; // This will cause an error!
// ❌ WRONG: Returning an Action instance
return new ProcessPayment(); // This will also cause an error!
}
✅ Correct - Call Action, Return State
public function next(Context $context, string $input): ?string
{
$this->setContext($context);
// ✅ CORRECT: Call the action to perform business logic
$action = new ProcessPayment();
$result = $action->handle($context, $input);
// ✅ CORRECT: Return a STATE class name based on the result
if ($result['success'] ?? false) {
return PaymentSuccessState::class; // State class name
}
return PaymentErrorState::class; // State class name
}
Key Points to Remember:
- Actions are called (invoked) within states to perform business logic
-
States are returned from
next()to navigate the flow -
The return type of
next()is?string- a State class name or null - Use actions for side effects (API calls, database operations), then return the appropriate next state