Forms
Forms let you easily create and update model objects. Usually they are used with streams
but are versatile enough to handle API forms, non-model forms, or any form requirements you have.
Builders
Form builders
are the entry point for creating a form. All forms will use a builder
to convert your basic component definitions
into their respective classes.
Basic Usage
To get started building a form. First create a FormBuilder
that extends the \Anomaly\Streams\Platform\Ui\Form\FormBuilder
class.
When using the make:stream
command form builders are created for you. A generated form builder looks like this:
<?php namespace Example\TestModule\Test\Form;
use Anomaly\Streams\Platform\Ui\Form\FormBuilder;
class TestFormBuilder extends FormBuilder
{
/**
* The form fields.
*
* @var array|string
*/
protected $fields = [];
/**
* Fields to skip.
*
* @var array|string
*/
protected $skips = [];
/**
* Additional validation rules.
*
* @var array|string
*/
protected $rules = [];
/**
* The form actions.
*
* @var array|string
*/
protected $actions = [];
/**
* The form buttons.
*
* @var array|string
*/
protected $buttons = [];
/**
* The form options.
*
* @var array
*/
protected $options = [];
/**
* The form sections.
*
* @var array
*/
protected $sections = [];
/**
* The form assets.
*
* @var array
*/
protected $assets = [];
}
FormBuilder::$fields
Form fields
are the primary building block of a form. Fields define the inputs for your form. If your form uses a stream model then most of the work can be automated for you. However you can also define fields 100% manually too.
Example
protected $fields = [
'database_driver' => [
'label' => 'anomaly.module.installer::field.database_driver.label',
'instructions' => 'anomaly.module.installer::field.database_driver.instructions',
'type' => 'anomaly.field_type.select',
'value' => env('DB_DRIVER', 'mysql'),
'required' => true,
'rules' => [
'valid_database',
],
'validators' => [
'valid_database' => [
'handler' => DatabaseValidator::class,
'message' => false,
],
],
'config' => [
'options' => [
'mysql' => 'MySQL',
'pgsql' => 'Postgres',
'sqlite' => 'SQLite',
'sqlsrv' => 'SQL Server',
],
],
],
'database_host' => [
'label' => 'anomaly.module.installer::field.database_host.label',
'placeholder' => 'anomaly.module.installer::field.database_host.placeholder',
'instructions' => 'anomaly.module.installer::field.database_host.instructions',
'type' => 'anomaly.field_type.text',
'value' => 'localhost',
'required' => true,
],
'database_name' => [
'label' => 'anomaly.module.installer::field.database_name.label',
'placeholder' => 'anomaly.module.installer::field.database_name.placeholder',
'instructions' => 'anomaly.module.installer::field.database_name.instructions',
'value' => env('DB_DATABASE', snake_case(strtolower(config('streams::distribution.name')))),
'type' => 'anomaly.field_type.text',
'required' => true,
],
];
FormBuilder::$skips
The skips
property is for defining fields to skip. Simply include an array of field slugs.
Example
protected $skips = [
'example_field',
];
FormBuilder::$rules
The rules
property is for defining additional field rules.
Example
protected $rules = [
'example_field' => [
'required',
'date:n-j-Y',
],
];
FormBuilder::$sections
Form sections
help you organize your fields into different field group layouts.
Example
protected $sections = [
'license' => [
'fields' => [
'license',
],
],
'database' => [
'fields' => [
'database_driver',
'database_host',
'database_name',
'database_username',
'database_password',
],
],
'administrator' => [
'fields' => [
'admin_username',
'admin_email',
'admin_password',
],
],
'application' => [
'fields' => [
'application_name',
'application_reference',
'application_domain',
'application_locale',
'application_timezone',
],
],
];
FormBuilder::$actions
Form actions
determine what your form does when submitted. Most actions assume the form saves and then does something else like redirect to a new form or the same form to continue editing the entry but they can do anything else you need like submitting to APIs or redirecting somewhere.
Example
protected $actions = [
'save',
'save_create',
];
FormBuilder::$buttons
Form buttons
extend base UI buttons and allow you to add simple button links to your form. Form buttons
do not submit the form.
Example
protected $buttons = [
'cancel',
'view',
];
FormBuilder::$options
Form options
help configure the behavior in general of the form. You can use options for toggling specific UI on or off, adding a simple title and description, or pushing data into the form view.
Example
protected $options = [
'redirect' => 'admin/products/view/{entry.id}'
];
FormBuilder::$assets
The assets
property defines assets to load to load for the form.
Example
protected $assets = [
'scripts.js' => [
'theme::js/forms/initialize.js',
'theme::js/forms/validation.js',
],
'styles.css' => [
'theme::scss/forms/validation.scss',
]
];
Ajax Forms
You can easily make forms use ajax behavior by setting the $ajax
property.
protected $ajax = true;
You can also flag forms as ajax on the fly.
$builder->setAjax(true);
Ajax forms are designed to be included in a modal by default but you can configure it to display like a normal form or however you like.
Read-only Forms
To render the form as read-only
just set the $readOnly
flag on the builder
.
protected $readOnly = true;
You can also set this flag on the fly:
$builder->setReadOnly(true);
Form Handlers
Form handlers
are responsible for handling the business logic of the form. Generally this is to simply save the form.
The default form handler for example looks like this:
<?php namespace Anomaly\Streams\Platform\Ui\Form;
class FormHandler
{
/**
* Handle the form.
*
* @param FormBuilder $builder
*/
public function handle(FormBuilder $builder)
{
if (!$builder->canSave()) {
return;
}
$builder->saveForm();
}
}
Writing Custom Handlers
You can use your own form handler by defining it in your form builder. Simply define the self handling class or a callable class string.
protected $handler = \Example\Test\MyCustomHandler::class; // Assumes @handle
protected $handler = 'Example\Test\AnotherCustomHandler@test';
Now in your form handler you can add your own logic.
class MyCustomHandler
{
public function handle(MyCustomFormBuilder $builder)
{
if ($builder->hasFormErrors()) {
return; // We have errors.. abandon ship!
}
// Do amazing stuff here.
}
}
Form Models
Form models
are used to determine the form repository to use and provide the model for the system to use when creating and updating an entry.
Form models
are guessed based on the form builders class. If using php artisan make:stream
the model property does not need to be set.
If you would like to or have to define the model yourself you can do so on the form builder
.
protected $model = \Anomaly\UsersModule\User\UserModel::class;
Form Repositories
Form repositories
are used to create an entry when creating and to update an entry when editing. The repository is guessed based on the type of model used.
If you would like to or need to define the repository yourself you can do so on the form builder
.
protected $repository = \Example\Test\FancyFormRepository::class;
The form repository must implement \Anomaly\Streams\Platform\Ui\Form\Contract\FormRepositoryInterface
and implement the following methods:
/**
* Find an entry or return a new one.
*
* @param $id
* @return mixed
*/
public function findOrNew($id);
/**
* Save the form.
*
* @param FormBuilder $builder
* @return bool|mixed
*/
public function save(FormBuilder $builder);
Including Assets
Besides the obvious overriding views to include your own assets you can also specify assets to include with the $assets
array.
Specify the assets to include per the collection they should be added to.
protected $assets = [
'scripts.js' => [
'theme::js/form/initialize.js',
'theme::js/form/example.js',
],
'styles.css' => [
'theme::scss/form/example.scss',
]
];
Fields
Form fields
are the main building blocks of forms. They control the inputs
first but also the way data is handled when saving and everything in between.
The Field Definition
Below is a list of all available field definition properties.
Properties
Key | Required | Type | Default | Description |
---|---|---|---|---|
$slug |
true |
string |
The field definition key. |
The field slug is used for naming the field input and identifying it amongst other fields. |
$label |
false |
string |
The field assignment label or field name if available. |
The input label. |
$instructions |
false |
string |
The field assignment instructions or field instructions. |
The input instructions. |
$warning |
false |
string |
The field assignment warning or field warning. |
The input warning. |
$placeholder |
false |
string |
The field assignment placeholder or field placeholder. |
The input placeholder. |
$type |
false |
string |
The field type. |
The namespace or slug of a field type to use. |
$field |
false |
string |
The streams field slug. |
The streams field slug to use for populating defaults. |
$required |
false |
boolean |
The required status of the field assignment. |
A shortcut boolean flag to add |
$unique |
false |
boolean |
The unique status of the field assignment. |
A shortcut boolean flag to add |
$rules |
false |
array |
null |
An array of additional Laravel validation rules. |
$validators |
false |
array |
null |
An array of custom validators keyed by rule. |
$prefix |
false |
string |
The prefix of the form. |
The prefix helps when more than one form are displayed on a page. |
$disabled |
false |
boolean |
false |
Determines whether the field will be disabled or not. |
$enabled |
false |
boolean |
true |
Determines whether the field will be processed or not. |
$readonly |
false |
boolean |
false |
Determines whether the field will be read only or not. |
$hidden |
false |
boolean |
false |
Determines whether the field will be visibly hidden or not. |
$config |
false |
array |
null |
A config array for the field type. |
$attributes |
false |
array |
null |
An array of |
$class |
false |
string |
Varies by field type. |
A class to append to the attributes. |
$input_view |
false |
string |
Varies by field type. |
A prefixed view to use for the input. |
$wrapper_view |
false |
string |
Varies by field type. |
A prefixed view to use for the field wrapper. |
Sections
Sections help you organize your fields into different field groups.
The Section Definition
Below is a list of all possible section definition properties available.
Properties
Key | Required | Type | Default | Description |
---|---|---|---|---|
slug |
true |
string |
The definition key. |
The section slug can be used to reference the section later. |
title |
false |
string |
{vendor}.module.{module}::{slug}.title |
The section title. |
description |
false |
string |
{vendor}.module.{module}::{slug}.description |
The section description. |
fields |
false |
array |
null |
The section fields. |
tabs |
false |
array |
null |
The section tab definitions. See below for more information. |
attributes |
false |
array |
null |
An array of |
view |
false |
string |
null |
The view to delegate the section to. |
The Tab Definition
Here is a list of all available tab properties.
Properties
Key | Required | Type | Default | Description |
---|---|---|---|---|
slug |
true |
string |
The definition key. |
The tab slug is used in it's HTML markup as part of an ID. |
title |
true |
string |
none |
The tab title. |
stacked |
false |
boolean |
|
If |
fields |
false |
array |
null |
The tab fields. |
Standard Sections
Standard sections simply stack fields on top of each other in a single group.
protected $sections = [
'database' => [
'title' => 'Database Information',
'fields' => [
'database_driver',
'database_host',
'database_name',
'database_username',
'database_password'
]
],
'administrator' => [
'title' => 'Admin Information',
'fields' => [
'admin_username',
'admin_email',
'admin_password'
]
],
];
Tabbed Sections
Tabbed sections allow separating fields in the section into tabs.
protected $sections = [
'general' => [
'tabs' => [
'form' => [
'title' => 'module::tab.form',
'fields' => [
'form_name',
'form_slug',
'form_description',
'success_message',
'success_redirect'
]
],
'notification' => [
'title' => 'module::tab.notification',
'fields' => [
'send_notification',
'notification',
'notification_send_to',
'notification_cc',
'notification_bcc'
]
],
]
]
];
Section Views
You can also define a view to handle the entire section.
protected $sections = [
'general' => [
'view' => 'module::form/general',
],
'advanced' => [
'view' => 'module::form/advanced',
],
];
Actions
Form actions
determine what your form does when submitted. Most actions assume the form saves and then does something else like redirect to a new form or the same form to continue editing the entry.
The Action Definition
Below is a list of all action specific definition properties. Actions extend buttons so you can refer to button documentation for a complete set of options for buttons.
Properties
Key | Required | Type | Default | Description |
---|---|---|---|---|
slug |
true |
string |
The definition key. |
The action becomes the submit button's name. |
redirect |
false |
string |
Back to the form. |
The action redirect URL. |
handler |
false |
string |
null |
A callable class string. This is useful when you want to include additional logic when a form is submitted using an action. |
Defining Actions
A standard
action usually modifies the redirect but can also define a handler
to perform extra logic too.
protected $actions = [
'button' => 'save',
'redirect' => 'admin/products/view/{entry.id}',
];
Using Registered Actions
There are a number of actions registered in the \Anomaly\Streams\Platform\Ui\Form\Component\Action\ActionRegistry
class. To use any of these actions simply include their registered string slug.
protected $actions = [
'save',
];
The simple slug get's populated from the registered button like this:
protected $actions = [
'save' => [
'button' => 'save',
'text' => 'streams::button.save'
],
];
Overriding Registered Actions
Just like other definitions either registered or automated, you can include more information in your definition to override things.
protected $actions = [
'save' => [
'text' => 'Save Me!'
],
];
The Action Registry
Below are the basic registered actions. Note the button options that will in turn automate more action properties based on registered buttons. Actions may also simply be registered buttons themselves and allow default handling behavior. Experiment with it!
Registered actions can be found in Anomaly\Streams\Platform\Ui\Form\Component\Action\ActionRegistry
.
'update' => [
'button' => 'update',
'text' => 'streams::button.update'
],
'save_exit' => [
'button' => 'save',
'text' => 'streams::button.save_exit'
],
'save_edit' => [
'button' => 'save',
'text' => 'streams::button.save_edit'
],
'save_create' => [
'button' => 'save',
'text' => 'streams::button.save_create'
],
'save_continue' => [
'button' => 'save',
'text' => 'streams::button.save_continue'
],
'save_edit_next' => [
'button' => 'save',
'text' => 'streams::button.save_edit_next'
],
Options
Form options
help configure the behavior in general of the form. Anything from toggling specific UI on or off to adding a simple title and description can be done with the form options.
protected $options = [
'title' => 'My awesome form!',
'form_view' => 'module::my/custom/form'
];
You can also set/add options from the API.
$builder->addOption('url', 'http://domain.com/example/api');
Available Options
Below is a list of all available options for forms.
Properties
Key | Required | Type | Default | Description |
---|---|---|---|---|
form_view |
false |
string |
streams::form/form |
The form view is the primary form layout view. |
wrapper_view |
false |
string |
streams::blank |
The wrapper view is the admin layout wrapper. This is the view you would override if you wanted to include a sidebar with your form for example. |
permission |
false |
string |
{vendor}.module.{module}::{stream}.write |
The permission string required to access the form. |
url |
false |
string |
The route displaying the form (submits to itself). |
The URL for the form submission. This is generally automated but varies depending on how the form is being used. |