Without the facade
The facade is the recommended default, not a requirement. The facade root, RoundlyConsulting\Onboarding\OnboardingManager, is a container singleton — inject it through the constructor for exactly the same API, as an explicit dependency with no static calls:
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use RoundlyConsulting\Onboarding\OnboardingManager;
final class OnboardingController
{
public function __construct(private OnboardingManager $onboarding) {}
public function show(Request $request): JsonResponse
{
return response()->json($this->onboarding->for($request->user())?->toData());
}
public function dismiss(Request $request, string $step): RedirectResponse
{
$this->onboarding->for($request->user())?->dismiss($step);
return back();
}
}Onboarding::fake() swaps the container binding as well as the facade, so an injected OnboardingManager gets the fake too.
No action classes
Unlike most Roundly packages, Onboarding ships no actions to compose: flows and steps are declarative, and the manager registers, resolves and persists them. The facade and the injected manager are the two entry points.
Manager methods
| Method | Returns | Purpose |
|---|---|---|
register($key, $flow = null) / flow(string $key) | OnboardingManager / Flow | Register a flow (steps array, Flow or class) / start one fluently. |
for($subject, ?string $key = null) | ?Flow | A copy of the subject’s flow, bound to it. |
find(string $key, ?Flow $default = null) | ?Flow | The registered definition. |
has() / all() / forget() / flush() | — | Inspect and edit the registry. |
resolveUsing(Closure) / resolveFor($subject, ?string $fallback = null) | OnboardingManager / ?Flow | Pick the flow per subject. |
useStore(OnboardingStore|string $store) | OnboardingManager | Configure persistence. |
store() / hasStore() | ?OnboardingStore / bool | The store in use. |
dismissStep(Flow $flow, string $step) is public but @internal — the single path every dismissal takes, so the fake sees them all. Dismiss through Flow::dismiss() or $user->dismissOnboardingStep() instead.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.