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();
}