Decision
The Decision component allows you to handle user inputs and navigate to different states based on those inputs. It provides a fluent interface for creating decision trees and validating user input.
Understanding Decisions
Decisions are used in the next() method of states to determine which state the user should see next based on their input. The Decision class provides various validation methods that can be chained together to create complex decision logic.
Basic Usage
Decisions are typically used in state classes to route users based on their input:
<?php
namespace App\Ussd\States;
use Vendor\LaravelUssd\Support\AbstractState;
use Vendor\LaravelUssd\Support\Context;
class WelcomeState extends AbstractState
{
public function next(Context $context, string $input): ?string
{
$this->setContext($context);
return $this->decision($input)
->equal('1', BalanceState::class)
->equal('2', TransferState::class)
->equal('3', null) // End session
->any(WelcomeState::class); // Default fallback
}
}
Decision Methods
equal($value, $state)
Checks if the input exactly matches the given value. If true, transitions to the specified state.
$this->decision($input)->equal('1', MenuState::class);
numeric($state)
Checks if the input is numeric. Transitions to the specified state if the input contains only numbers.
$this->decision($input)->numeric(AmountState::class);
integer($state)
Checks if the input is a valid integer. Transitions to the specified state if the input is a whole number.
$this->decision($input)->integer(QuantityState::class);
amount($state)
Validates that the input is a valid monetary amount. Useful for payment or transfer flows.
$this->decision($input)->amount(PaymentState::class);
length($min, $max, $state)
Checks if the input length is between the minimum and maximum values (inclusive).
$this->decision($input)->length(4, 6, PinState::class);
phoneNumber($state)
Validates that the input is a valid phone number format.
$this->decision($input)->phoneNumber(RecipientState::class);
between($min, $max, $state)
Checks if the numeric input is between the minimum and maximum values (inclusive).
$this->decision($input)->between(1, 5, OptionState::class);
in(array $values, $state)
Checks if the input is one of the values in the provided array.
$this->decision($input)->in(['yes', 'y', '1'], ConfirmState::class);
custom(callable $callback, $state)
Allows you to define custom validation logic using a callback function.
$this->decision($input)->custom(function($input) {
return str_starts_with($input, 'ACC');
}, AccountState::class);
any($state)
Acts as a catch-all that matches any input. Should be used as the last method in the chain as a fallback.
$this->decision($input)->any(ErrorState::class);
Chaining Methods
Decision methods can be chained together to create complex decision trees. The first matching condition will determine the next state:
public function next(Context $context, string $input): ?string
{
$this->setContext($context);
return $this->decision($input)
->equal('0', WelcomeState::class) // Return to main menu
->equal('99', null) // End session
->between(1, 5, SelectedOptionState::class) // Valid option range
->numeric(InvalidInputState::class) // Numeric but out of range
->any(ErrorState::class); // Any other input
}
Complete Example
<?php
namespace App\Ussd\States;
use Vendor\LaravelUssd\Support\AbstractState;
use Vendor\LaravelUssd\Support\Context;
use Vendor\LaravelUssd\Support\UssdResponse;
class TransferAmountState extends AbstractState
{
public function entry(Context $context): UssdResponse
{
return UssdResponse::continue(
"Enter amount to transfer:\n" .
"Minimum: 10\n" .
"Maximum: 5000"
);
}
public function next(Context $context, string $input): ?string
{
$this->setContext($context);
// Store amount in context for later use
$this->record->set('amount', $input);
return $this->decision($input)
->amount(ConfirmTransferState::class)
->between(10, 5000, ConfirmTransferState::class)
->numeric(InvalidAmountState::class)
->any(ErrorState::class);
}
}