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.

**Note:** Actions extend UI buttons so some actions may use registered buttons to further automate themselves.

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.

**In Development:** The Ajax API is still being developed. While ajax forms are usable, more robust JSON response information is still missing.
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.
    }
}
**Pro Tip:** Handlers are called using the **Service Container** and support class and method injection.
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 required to the rules array.

$unique

false

boolean

The unique status of the field assignment.

A shortcut boolean flag to add unique to the rules array.

$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 key => value HTML attributes. Any base level definition keys starting with data- will be pushed into attributes automatically.

$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 key => value HTML attributes. Any base level definition keys starting with data- will be pushed into attributes automatically.

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

false

If true then tabs will stack vertically.

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.