All packages
Onboarding for Laravel
Extending & exceptions
Flow, Step and OnboardingManager all use Laravel’s Macroable trait, so you can add fluent helpers at boot without subclassing:
use RoundlyConsulting\Onboarding\Flow;
use RoundlyConsulting\Onboarding\OnboardingManager;
use RoundlyConsulting\Onboarding\Step;
// e.g. in a service provider's boot()
Step::macro('completeWhenVerified', fn () => $this->completeWhenTrue('email_verified_at'));
Flow::macro('progressLabel', fn () => round($this->percentageCompleted()).'% done');
OnboardingManager::macro('keys', fn () => $this->all()->keys());Step::make('Verify email')->completeWhenVerified();
$user->onboarding()?->progressLabel(); // "67% done"
Onboarding::keys(); // Collection of registered flow keysOther extension points
- Custom flow classes — extend Flow and configure it in setup().
- The resolver — Onboarding::resolveUsing() picks a flow per subject.
- defaultOnboardingKey() — override it on a model to choose its flow.
- The OnboardingStore contract — plug in your own with Onboarding::useStore() for dismissible steps and once-only events.
- Events — listen to StepCompleted and FlowCompleted to persist progress or trigger side effects.
Exceptions
| Exception | Extends | Thrown when |
|---|---|---|
OnboardingException | InvalidArgumentException | Base type for the package’s exceptions. |
InvalidFlowException::keyMustBeString() | OnboardingException | register() received a non-string key together with a flow. |
InvalidFlowException::notAFlowClass($class) | OnboardingException | A class string that is not Flow or a subclass was registered. |
InvalidStoreException::notAStore($class) | OnboardingException | useStore() received a class that doesn’t implement OnboardingStore. |
use RoundlyConsulting\Onboarding\Exceptions\InvalidFlowException;
use RoundlyConsulting\Onboarding\Facades\Onboarding;
try {
Onboarding::register(SomeNonFlowClass::class);
} catch (InvalidFlowException $e) {
// "[App\SomeNonFlowClass] is not a RoundlyConsulting\Onboarding\Flow class."
}OnboardingException extends InvalidArgumentException, so existing catch (InvalidArgumentException) blocks keep working.
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.