🪄 Work in progress
This documentation is still a work in progress, so please don’t mind the mess. We also want to assure you that any corpses you see are used for completely legal and sanctioned necromantic purposes. Absolutely no funny business is taking place here.
This page is meant as an example to get you started with
as quickly as possible
as long as the rest of the documentation is still in shambles.
Creating the wizard
To get started, let’s create a new folder called
Wizards in our
app directory. Inside this folder, let’s create another folder called
Registration. In here, we add a new class called
RegistrationWizard which will be the starting point of our wizard.
The folder structure doesn’t actually matter. But since each wizard will consist of multiple classes it makes sense to group them like this.
Let’s quickly go through the different fields that are included in the wizard scaffolding and what they’re used for:
$title- This should be a human-readable title for your wizard. While this will not be displayed anywhere by default, it gets passed to your templates so you can display it the frontend.
$slug- The slug gets used for the URLs and route names that get registered for a wizard, as well as resolving the path to the wizard’s templates (more on that later).
$onCompleteAction- The action that gets called after the last step of the wizard was successfully completed. The action is where the actual business logic of your form should happen. I’ve already prefilled a class called
RegistrationActionwhich we will create later in this tutorial.
$steps- The list of steps that make up the wizard. Note that the order in which steps are listed here is important since Arcanist uses that to determine which step comes next and when the wizard is complete.
middleware()- If you want to register custom middleware for a specific wizard, you can implement this method. It should return an array of additional middleware which will get merged with the global middleware configured in the
sharedData()- If you have data that should be shared with each step, you can configure this here. This will get merged with the
viewDataof the step itself.
Registering the wizard
In order for
to know about our new wizard, we have to register it in the
wizards array of our
arcanist.php config file.
Doing so will register all required routes for our new wizard so we’re ready to start using it. Let’s take a quick look at our application routes:
If you try to visit any of these routes right now, however, you will get an exception. That’s because our wizard currently doesn’t have any steps. So let’s do that next.
To keep this example simple, our wizard will only consist of two steps:
UsernameAndPasswordStepwhich gathers the user’s username and password (shocker!)
AnnoyingNewsletterStepwhere we will try to trick the user into signing up for our wizard-related newsletter
Since a wizard with only a single step is just a form, every wizard needs at least two steps to work properly.
Let’s create a new folder
Steps and add the following two classes:
Before we forget, let’s make sure to add these steps to our wizard’s
How steps are structured
Let’s take a look at the
UsernameAndPasswordStep scaffolding and see what we’re working with:
$title- Similar to the title of our wizard, this should be a human-readable title for the step. The title will get passed to the template so that you may display it in the frontend. Or don’t. I’m not your dad.
$slug- The slug is used for the URL of the step as well as for determining the name of the step’s template.
viewData()- The return value of this function is what gets passed to the step’s template, together with any shared data defined in the wizard. More about this later.
fields()- In this method you should define the fields that exist on this step of the form as well as any validation rules that go along with them. In other words, this is how Arcanist knows what data it should save when the step gets submitted.
In order for
to understand how it should deal with incoming requests, we need to tell it which fields exist on a step. We can use the
Field class to fluently build up our field definitions.
To define validation rules, we can define validation rules for our fields using Laravel’s validation rules.
Field::make('username') ->rules(['required', 'unique:users,username'])
With this information,
will use Laravel’s request validation to check the incoming request for the step. This means that in your blade templates you can use Laravel’s built-in
@error directive to conditionally display validation errors.
Here’s what our steps look like after filling in the field definitions.
The user’s password would currently get saved as plaintext in the wizard’s data. There are ways to hook into the step’s lifecycle to make sure that we encrypt the password before saving it. To keep this example simple, we will not do this here.
Passing data to view
In order to pass data to our step templates, we can use the
viewData() method on the step class.
withFormData()convenience method. This method ensures that data that has already been collected for any of the step’s fields is included in the view data.
Assuming we have a step that defines a
billingCycle field, these two ways would be equivalent.
Accessing wizard data
You can access any data—from any step—that has previously been collected by using the
$this->data(string $key, mixed $default = null) method on the step.
Views Arcanist is completely frontend agnostic. As such, it does not come with any templates. Views are highly application-specific and there is really no sensible defaults this package could provide.
Instead, you’re supposed to create your own views for each step of the wizard. Out of the box, Arcanist ships only with a Blade based template renderer. The way it tries to resolve the path of a step’s template is by using the following convention:
So in our example,
expects the template for our
UsernameAndPasswordStep to exist at
Once we create this file, we can now navigate to
/wizard/registration and view the first step in our wizard.
Accessing data in a view
Every step template gets passed two pieces of data by Arcanist .
- Metadata about the current wizard and its steps, accessible via the
$wizardvariable in our template
- The step-specific data defined in the
viewDatamethod of the step, accessible via the
In our example, the
$wizard variable would contain the following data:
The wizard’s id is current
null since we’re viewing the wizard for the first time. Only after the user has successfully submitted the first step will
start keeping track of the wizard.
steps key contains the list of all steps that have been registered for the wizard, together with metadata about each of them.
slug- The step’s slug
isComplete- If the step has already been completed. Arcanist keeps track of this behind the scenes. You can use this value to style completed steps differently in your templates, for example.
title- The step’s title.
active- If the step is the currently active one (i.e. we’re viewing its template). Again, this can be used to highlight the current step in your UI.
url- The url to the step. This is currently empty, because the wizard has not been saved yet.
Using this data, you can build up the UI of your wizard. Since the data inside
$wizard stays the same across all steps of a wizard, it is a good candidate to be extracted into a layout or Blade component that can then be reused for all wizards. Only the step templates have to be created individually.
After the last step in a wizard was successfully completed,
will call then call the wizard’s configured
A big design idea of Arcanist is that the steps don’t perform any business logic. All they do is collect data that will then be handed of to the action at the end of the wizard. Actions are the place where your actual business logic happens.
Let’s create a simple
RegistrationAction for our wizard:
An action is simply a class which extends from
WizardAction. This class needs to implement a single method
execute which gets passed the wizard’s data and needs to return an
To no one’s surprise, an
ActionResult represents the result of calling a wizard’s action. Since it’s possible that an exception might occur inside the action, an
ActionResult can represent both a successful and a failed state.
handles this state internally to either complete the wizard (and delete it) or redirect back to the last step with an error.
If the action returns a failed result (by using
$this->error(...)), we can access the error message in our templates via the
wizard key in the error bag.
In case you need to pass data back to the wizard from the action, you can provide an associative array to the
success method of the action.