1. Go to this page and download the library: Download juststeveking/scenario library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
juststeveking / scenario example snippets
readonly class RegisterUserData
{
public function __construct(public string $name, public string $email) {}
}
use JustSteveKing\Scenario\Contracts\Action;
use JustSteveKing\Scenario\Context\Context;
use JustSteveKing\Scenario\Support\Result;
class CreateUser implements Action
{
public function handle(RegisterUserData $data): Result
{
$user = new User($data->name, $data->email);
$user->save();
return Result::success($user); // $user is recorded in Context automatically
}
public function compensate(mixed $input, Context $context): void
{
$context->get(User::class)?->delete();
}
}
use JustSteveKing\Scenario\Contracts\Scenario;
use JustSteveKing\Scenario\Engine\Blueprint;
class RegistrationScenario implements Scenario
{
public function build(Blueprint $plan): void
{
$plan->add(CreateUser::class)
->add(SendWelcomeEmail::class);
}
}
use JustSteveKing\Scenario\Scenario;
Scenario::for(RegistrationScenario::class)
->run(new RegisterUserData('John Doe', '[email protected]'))
->onSuccess(function (Context $context): void {
$user = $context->get(User::class);
// $user is the object returned by CreateUser
})
->onFailure(function (string $error, Context $context): void {
// $error is the message from Result::failure(...)
// $context holds any objects recorded before the failure
});
$pending = Scenario::for(RegistrationScenario::class)
->through([LoggingMiddleware::class, DatabaseTransactionMiddleware::class]) // optional, outermost first
->onStep(function (string $action, Result $result, Context $context): void {
// fires after every action, success or failure
})
->run(new RegisterUserData('John Doe', '[email protected]'))
->onSuccess(function (Context $context): void {
// fires once if the whole scenario succeeded
$user = $context->get(User::class);
})
->onFailure(function (string $error, Context $context): void {
// fires once if any action returned Result::failure(...)
});
// Escape hatches — useful in tests or when you need the result outside a callback
$result = $pending->result(); // ?Result
$context = $pending->context(); // Context
class SendWelcomeEmail implements Action
{
public function __construct(private Mailer $mailer) {}
// User comes from Context (returned by the previous CreateUser action).
// RegisterUserData comes from the initial run() input.
// Mailer is resolved from the container.
public function handle(User $user, RegisterUserData $data): Result
{
$this->mailer->send($user->email, $data->name);
return Result::success();
}
public function compensate(mixed $input, Context $context): void {}
}
class CreateOrder implements Action
{
public function handle(CheckoutData $data): Result
{
$order = Order::create($data);
return Result::success($order);
}
public function compensate(mixed $input, Context $context): void
{
// Called if a later step fails — undo the order creation
$context->get(Order::class)?->delete();
}
}
use JustSteveKing\Scenario\Contracts\Middleware;
class MyMiddleware implements Middleware
{
public function handle(mixed $input, Context $context, Closure $next): Result
{
// Before execution
$result = $next($input, $context);
// After execution
return $result;
}
}
Scenario::for(CheckoutScenario::class)
->through([MyMiddleware::class])
->run($input);
use JustSteveKing\Scenario\Middleware\LoggingMiddleware;
Scenario::for(CheckoutScenario::class)
->through([LoggingMiddleware::class])
->run($input);
use JustSteveKing\Scenario\Middleware\DatabaseTransactionMiddleware;
Scenario::for(CheckoutScenario::class)
->through([DatabaseTransactionMiddleware::class])
->run($input);
Scenario::for(CheckoutScenario::class)
->onStep(function (string $action, Result $result, Context $context): void {
// $action — fully-qualified class name of the action that just ran
// $result — its Result; check isSuccess() / isFailure()
// $context — context at this point; on success the action's return
// value is already recorded here
})
->run($input);
class SendNotification implements Action
{
// 'channel' and 'priority' are matched by parameter name from the payload
public function handle(string $channel, string $priority): Result
{
// send via $channel at $priority...
return Result::success();
}
public function compensate(mixed $input, Context $context): void {}
}
class OrderScenario implements Scenario
{
public function build(Blueprint $plan): void
{
$plan->add(CreateOrder::class)
->add(SendNotification::class, ['channel' => 'email', 'priority' => 'high'])
->add(SendNotification::class, ['channel' => 'slack', 'priority' => 'low']);
}
}
class ValidationScenario implements Scenario
{
public function build(Blueprint $plan): void
{
$plan->add(ValidateAddress::class)
->add(ValidatePaymentMethod::class);
}
}
class CheckoutScenario implements Scenario
{
public function build(Blueprint $plan): void
{
$plan->add(ValidationScenario::class) // entire sub-scenario runs as one step
->add(ReserveInventory::class)
->add(ChargePayment::class)
->add(SendConfirmation::class);
}
}
use JustSteveKing\Scenario\Scenario;
public function test_it_dispatches_registration_scenario()
{
Scenario::fake();
$this->post('/register', [
'name' => 'John',
'email' => '[email protected]',
]);
// Assert it ran at all
Scenario::assertRan(RegistrationScenario::class);
// Or assert it ran with specific input
Scenario::assertRan(RegistrationScenario::class, function ($input) {
return $input->email === '[email protected]';
});
Scenario::assertNotRan(DeleteUserScenario::class);
}
public function test_registration_scenario_succeeds()
{
Scenario::for(RegistrationScenario::class)
->run(new RegisterUserData('John', '[email protected]'))
->assertPassed()
->assertContextHas(User::class)
->assertContextHas(User::class, fn(User $user) => $user->email === '[email protected]');
}
public function test_registration_scenario_fails_on_duplicate_email()
{
Scenario::for(RegistrationScenario::class)
->run(new RegisterUserData('John', '[email protected]'))
->assertFailed();
}
public function test_checkout_handles_payment_failure()
{
Scenario::for(CheckoutScenario::class)
->mock(ChargeCreditCard::class, Result::failure("Card declined."))
->run(new CheckoutData())
->assertFailed();
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.