Combining Form Builders
- Posted March 30, 2017
- Developer Tools
- Advanced
Introduction
Form builders are based on the concept of a single model and therefor represent a single stream data structure. However you can leverage multiple form builders
to combine multiple form builders into one.
Basic Usage
Let's assume for this example that we want to combine forms for a user and customer information that is tied to a given user.
To begin first create a form builder that extends \Anomaly\Streams\Platform\Ui\Form\Multiple\MultipleFormBuilder
like this:
<?php namespace Anomaly\StoreModule\Customer\Form;
use Anomaly\Streams\Platform\Ui\Form\Multiple\MultipleFormBuilder;
class RegisteredCustomerFormBuilder extends MultipleFormBuilder
{
...
}
Since the a form builder for the user stream already exists in core we will only need a form builder for the customer stream. Let's assume that the CustomerFormBuilder
has already been created for us with the make:stream
command.
Combining Forms
The only required step in using a multiple form builder is adding the child forms to it. To add a form to the multiple form builder use the addForm
method. The first argument is a key
that is used as the prefix. If the key is customer
then the form being added will be prefixed customer_
. The second argument is the form builder instance:
$multiple->addForm('user', $userBuilder);
$multiple->addForm('customer', $customerBuilder);
All of the fields, skips, and validation are all inherited by the form that is added and will be run all the same.
Multiple Form Builder Sections
Just like with normal forms you may want to customize the layout and organization of fields within a multiple form builder. The process is the exact same in that you define sections on the multiple form builder's $sections
property. There is only one exception; You must refer to field including their form's prefix.
So a field with the slug of name
in the $customerBuilder
referenced above the field would be referenced in the multiple form builder's sections as customer_name
.
Tying Entries Together
Needing to combine multiple form builders often indicates that the entries need to force a relation between each other. To do this we will keep in mind our saving order and use callbacks to set information on the entries of the other forms.
When posting and saving the multiple form builders fire a special callback for each form builder specifically:
posting_{form_key}
posted_{form_key}
saving_{form_key}
saved_{form_key}
Let's use the saved
callback to pass the saved user
entry to our customer
entry being created which has a required relationship field with the slug of user
:
$multiple->on('saved_user', function() use ($multiple) {
$user = $multiple->getChildFormEntry('user');
$customer = $multiple->getChildFormEntry('customer');
$customer->user = $user;
});
We can also use bind
to register the callback. Using bind
will allow us to use $this
within the closure as if it were the multiple form builder. Similar to a native class function.
$multiple->bind('saved_user', function() {
$user = $this->getChildFormEntry('user');
$customer = $this->getChildFormEntry('customer');
$customer->user = $user;
});
Putting It Together
Let's put this all together in our controller method for creating a new registered customer:
public function create(RegisteredCustomerFormBuilder $form, CustomerFormBuilder $customer, UserFormBuilder $user)
{
$form->addForm('user', $user);
$form->addForm('customer', $customer);
$form->on('saved_user', function() use ($form) {
$user = $form->getChildFormEntry('user');
$customer = $form->getChildFormEntry('customer');
$customer->user = $user;
});
return $form->render();
}