simplon / form
Data validation & flexible form rendering incl. semantic-ui structure.
Installs: 6 559
Dependents: 3
Suggesters: 0
Security: 0
Stars: 4
Watchers: 2
Forks: 2
Open Issues: 0
Requires
- php: >=7.1
- fightbulc/moment: ^1.26
- simplon/component_form: ^0.2
- simplon/component_semanticui: ^0.0
- simplon/helper: ^1.0
- simplon/phtml: ^0.2
- dev-master
- 2.5.1
- 2.5.0
- 2.4.0
- 2.3.0
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.5
- 2.1.4
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.11
- 2.0.10
- 2.0.9
- 2.0.8
- 2.0.7
- 2.0.6
- 2.0.5
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 1.2.7
- 1.2.6
- 1.2.5
- 1.2.4
- 1.2.3
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.6
- 1.1.5
- 1.1.4
- 1.1.3
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.19
- 1.0.18
- 1.0.17
- 1.0.16
- 1.0.15
- 1.0.14
- 1.0.13
- 1.0.12
- 1.0.11
- 1.0.10
- 1.0.9
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- 0.6.8
- 0.6.7
- 0.6.6
- 0.6.5
- 0.6.4
- 0.6.3
- 0.6.2
- 0.6.1
- 0.6.0
- 0.5.9
- 0.5.8
- 0.5.7
- 0.5.6
- 0.5.5
- 0.5.4
- 0.5.3
- 0.5.2
- 0.5.1
- 0.5.0
- 0.4.4
- 0.4.3
- 0.4.2
- 0.4.1
- 0.4.0
- 0.3.15
- 0.3.14
- 0.3.13
- 0.3.12
- 0.3.11
- 0.3.10
- 0.3.9
- 0.3.8
- 0.3.7
- 0.3.6
- 0.3.5
- 0.3.4
- 0.3.3
- 0.3.2
- 0.3.1
- 0.3.0
- 0.2.5
- 0.2.4
- 0.2.3
- 0.2.2
- 0.2.1
- 0.2.0
- 0.1.5
- 0.1.4
- 0.1.3
- 0.1.2
- 0.1.1
- 0.1.0
- dev-feature/allow-unset-image-size
- dev-develop
- dev-feature/block-clones
- dev-php71-cleanup
- dev-block-cloning
This package is auto-updated.
Last update: 2024-10-29 04:14:33 UTC
README
_ _ __
___(_)_ __ ___ _ __ | | ___ _ __ / _| ___ _ __ _ __ ___
/ __| | '_ ` _ \| '_ \| |/ _ \| '_ \ | |_ / _ \| '__| '_ ` _ \
\__ \ | | | | | | |_) | | (_) | | | | | _| (_) | | | | | | | |
|___/_|_| |_| |_| .__/|_|\___/|_| |_| |_| \___/|_| |_| |_| |_|
|_|
Simplon/Forms
Simplon/Forms
helps to validate data and, if needed, to build a form view with a couple of widgets by leveraging Semantic-UI
library.
- Quick example
1.1 Fields
1.2 Validation
1.3 View - Fields
2.1 General fields
2.2 Fields with options
2.3 Rules
2.4 Filters - View
3.1 Simple example
3.2 Blocks & Rows
3.3 Elements - Block fields cloning
4.1 Building fields
4.2 Building view
4.3 Building templates - Settings
5.1 Field required/optinal label - Examples
1. Quick example
1.1 Fields
In order to validate data we need to create at least one field which can hold any number of rules to define its validity. A field can also hold any number of filters which will be applied to the field value.
Some field examples
// // easiest setup // (new FormFields())->add( new FormField('email') ); // // another way with a filter // (new FormFields())->add( (new FormField('email'))->addFilter(new CaseLowerFilter()) // lower case field value ); // // fields can also have rules // (new FormFields())->add( (new FormField('email')->addRule(new EmailRule()) // make sure that we get an email address ); // // we can also combine these things // (new FormFields())->add( (new FormField('email') ->addRule(new EmailRule()) ->addFilter(new CaseLowerFilter()) );
Pre-populating your fields
We can pre-poluate our fields with data we already have - not request
data:
// // our fields // $fields = (new FormFields())->add( (new FormField('email'))->addRule(new EmailRule()) ); // // set our data // $fields->applyInitialData( ['email' => 'foo@bar.com'] ); // // testing ... // $fields->get('email')->getInitialValue(); // foo@bar.com $fields->get('email')->getValue(); // foo@bar.com // // these values change if we enter for instance // "hello@bar.com" in our form and hit submit ... // $fields->get('email')->getInitialValue(); // foo@bar.com $fields->get('email')->getValue(); // hello@bar.com
1.2 Validation
FormValidation
is expecting at least one set of FormFields
. Let's pick up the example from above with an additional name
field. We set an empty array for our request data
. You can take the value from any source as long as its organised as an array.
// // request data // $requestData = [ 'name' => 'Johnny', 'email' => '', ]; // // define fields // $fields = new FormFields(); $fields->add( new FormField('name') ); $fields->add( (new FormField('email'))->addRule(new EmailRule()) ); // // validation // $validator = new FormValidator($requestData); if($validator->hasBeenSubmitted()) // any request data? { if($validator->validate()->isValid()) { // all validated field data as array var_dump($fields->getAllData()); } else { // array of error messages var_dump($validator->getErrorMessages()); // OR ... // array of error fields var_dump($validator->getErrorFields()); } }
FormValidator::hasBeenSubmitted
checks if our received data are empty or filled. In case we received data we can go ahead and run all applied rules over our defined fields by FormValidator::validate
and FormValidator::isValid
tells us if all fields passed their requirements.
In case of success we can collect all field values by FormFields::getAllData
. Otherwise you can check for errors by collecting the error messages via FormValidator::getErrorMessages
or by collecting all error fields FormValidator::getErrorFields
. The latter also holds all error messages by field.
1.3 View
In order to render your fields we need to apply them to Elements
. These elements can be applied to the FormView
directly or to a FormBlock
which renders our form automatically in a set structure. We will continue with our before defined fields:
// // define fields // $nameElement = (new InputTextElement($fields->get('name'))) ->setLabel('Email address') ->setDescription('Required in order to send you a confirmation'); $emailElement = (new InputTextElement($fields->get('email'))) ->setLabel('Email address') ->setDescription('Required in order to send you a confirmation'); // // apply to a block w/ one row // $block = (new FormViewBlock('default')) // set block ID to default ->addRow( (new FormViewRow()) ->autoColumns($nameElement) ->autoColumns($emailElement) ) ; // // set view // $formView = (new FormView())->addBlock($block);
We could set much more options but that should do it for now. Let's pass on our view to a template.
For the following example we assume that we have access to the $formView
variable. We simply pass on a form template to the FormView::render
method and include all core assets
:
<?php /** * @var FormView $formView */ use Simplon\Form\View\FormView; ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <title>simplon/form</title> <style type="text/css"> body { padding: 0; background: #fff; } </style> </head> <body> <div class="ui container"> <?= $formView->render(__DIR__ . '/form.phtml') ?> </div> <?= $formView->renderAssets() ?> </body> </html>
We separate our main template from the actual form template so that we can automatically render the required <form></form>
tags with all required attributes at the beginning and the end of the template. We also inject automatically the FormView
instance as $formView
variable.
<?php /** * @var FormView $formView */ use Simplon\Form\View\FormView; ?> <?php if ($formView->hasErrors()): ?> <div class="ui basic segment"> <?= $formView->renderErrorMessage() ?> </div> <?php endif ?> <div class="ui basic segment"> <?= $formView->getBlock('default')->renderBlock() ?> </div> <div class="ui basic segment"> <?= $formView->getSubmitElement()->renderElement() ?> </div>
Any validation errors would be rendered on top of the template. After this follows our defined block with the ID default
. This statement will render both of your fields next to each other with equal spacing. At the end you can place your Submit element
which comes in our example as an automatically set element. You can also define this field yourself.
2. Fields
Fields are an abstraction of your data and are by design very generic. The goal was that fields should work with incoming API requests as well as with the usual html forms.
2.1. General fields
Most of the fields simply require one rule and a filter. These would be most commonly RequiredRule
and the TrimFilter
. The latter comes already by default. What you definitely need is a field-id
which needs to be passed on with the constructor.
$field = (new FormField('name'))->addRule(new RequiredRule()) // required field with ID "name"
2.2. Fields with options
You might have fields which accept only a given set of values. In that case you can add options
as meta data to the field. Classic example would be an address field or a country selection.
$options = (new OptionsMeta()) ->add('DE', 'Germany') ->add('FR', 'France') ->add('US', 'United States') ; $field = (new FormField('shipping-to')) ->addMeta($options) ->addRule(new RequiredRule()) ;
2.3. Rules
There are a couple of common rules which we used so for all our form requirements. You can find them below. However, if you are in need to have some more rules it's very easy to add/extend rules. Just take a look at one of the existing rules to see how to do that.
RequiredRule
Mark a field to be required.
(new FormField('name'))->addRule(new RequiredRule())
UrlRule
Make sure that the field's value validates against a URL format.
(new FormField('website'))->addRule(new UrlRule()) // // set protocol if missing // (new FormField('website'))->addRule(new UrlRule('http')) // // allow only urls which hold foo.com // (new FormField('website'))->addRule( (new UrlRule())->setAdditionalRegex('/foo.com/') )
EmailRule
Make sure that the field's value validates against an email format.
(new FormField('email'))->addRule(new EmailRule())
ExactLengthRule
Make sure that the field's value validates against an exact length.
(new FormField('photos'))->addRule(new ExactLengthRule(5))
MaxLengthRule
Make sure that the field's value validates against a maximum length.
(new FormField('photos'))->addRule(new MaxLengthRule(5))
MinLengthRule
Make sure that the field's value validates against a minimum length.
(new FormField('photos'))->addRule(new MinLengthRule(1))
CallbackRule
Sometimes you need to run a check against the database or maybe to a cross-reference with some other fields. In that case this rule comes in handy. It lets you handle the validation and requires only the return of a boolean value to determine if the value is valid. We use it e.g. to make sure that the given email address is unique before we accept a new user registration.
First parameter takes the callback
and the second parameter is an optional error message
.
$callback = function(FormField $field) { $model = $this->db->read(['email' => $field->getValue()]); return $model === null; }; (new FormField('email'))->addRule(new CallbackRule($callback, 'Email address exists already'))
IfFilledRule
Sometimes we have optional fields which should only validate against a set of rules if they have a value. For this case we have this rule in place.
(new FormField('email'))->addRule(new IfFilledRule([new EmailRule()])
FieldDependencyRule
This rules lets you add rules to another field. Imagine that your actual field is an optional one and only if filled you want to validate some other fields.
$email = new FormField('email'); $depRule = new FieldDependencyRule($email, [new EmailRule()]); (new FormField('newsletter'))->addRule(new IfFilledRule([$depRule]))
WithinOptionsRule
Semantic-UI's drop-down field saves its selection in a hidden field. For multi-selection fields the selected values will be separated by a comma within that hidden field. To make sure that the submitted values still match your given options we can make use of WithinOptionsRule
.
$options = (new OptionsMeta()) ->add('DE', 'Germany') ->add('FR', 'France') ->add('US', 'United States') ; $field = (new FormField('shipping-to')) ->addMeta($options) ->addRule(new RequiredRule()) ->addRule(new WithinOptionsRule()) ;
2.4. Filters
A filter is run over your submitted field values. For instance, to make sure that a textfield does not include any white space characters you can add TrimFilter
to your field and simplon\form will make sure that your field value is cleared before processed further. Below is a list available filters but as for the rules you are able to add your own filters. Just take a look at one of the filters. Lastly, filters are combinable.
CaseLowFilter
Transform the field value to all lower-case.
(new FormField('email'))->addFilter(new CaseLowFilter()); // Foo@BAR.com --> foo@bar.com
CaseTitleFilter
Uppercase the first character of each word in the field's value.
(new FormField('name'))->addFilter(new CaseTitleFilter()); // foo bar --> Foo Bar
CaseUpperFilter
Uppercase the the complete field's value.
(new FormField('name'))->addFilter(new CaseUpperFilter()); // foo bar --> FOO BAR
TrimFilter
Each field holds this filter by default. Strip whitespace (or other characters) from the beginning and end of the field's value.
(new FormField('emai'))->addFilter(new TrimFilter()); // " foo@bar.com " --> "foo@bar.com"
You can override the default trimming characters by passing them through the filter's constructor:
(new FormField('emai'))->addFilter(new TrimFilter("$")); // "$foo@bar.com$" --> "foo@bar.com"
Instead of overriding the default trimming characters you can simply add characters:
(new FormField('emai'))->addFilter( (new TrimFilter())->addChars("$") ); // " foo@bar.com$" --> "foo@bar.com"
TrimLeftFilter
Same as for the TrimFilter
but only for the left-side of the field's value.
(new FormField('emai'))->addFilter(new TrimLeftFilter()); // " foo@bar.com" --> "foo@bar.com"
TrimRightFilter
Same as for the TrimFilter
but only for the right-side of the field's value.
(new FormField('emai'))->addFilter(new TrimRightFilter()); // "foo@bar.com " --> "foo@bar.com"
XssFilter
Use this filter to avoid XSS. The filter will try to catch and remove all html-related elements which seem to appear in your field's value.
(new FormField('comment'))->addFilter(new XssFilter()); // "A comment <script>...</script>" --> "A comment"
3. View
A view helps you to collect your fields in a structured way and to render them to display your form.
3.1. Simple example
For this example we would like to create a form for entering an email address. Remember that html structure is build on top of Semantic-UI's grid and widgets.
Code
// // fields // $emailId = 'email'; $fields = (new FormFields())->add( (new FormField($emailId))->addRule(new EmailRule()) ); // // validation // $validator = (new FormValidator($_POST))->addFields($fields)->validate(); if ($validator->hasBeenSubmitted()) { // do something when form is OK } // // build view // $view = (new FormView())->addElement( (new InputTextElement($fields->get($emailId)))->setLabel('Email address') ); // // render view // https://github.com/fightbulc/simplon_phtml // echo (new Phtml())->render('page.phtml', ['formView' => $view]);
Page template
/** * @var FormView $formView */ use Simplon\Form\View\FormView; ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <title>simplon/form</title> <link href="/assets/vendor/semantic-ui/2.2.x/semantic.min.css" rel="stylesheet"> <link href="/assets/vendor/simplon-form/base.min.css" rel="stylesheet"> </head> <body> <div class="ui container"> <?= $formView->render('form.phtml') ?> </div> <script src="/assets/vendor/jquery/3.2.x/jquery.min.js"></script> <script src="/assets/vendor/semantic-ui/2.2.x/semantic.min.js"></script> <script src="/assets/vendor/simplon-form/base.min.js"></script> <?= $formView->renderAssets() ?> </body> </html>
Form template
/** * @var FormView $formView */ use Simplon\Form\View\FormView; ?> <?php if ($formView->hasErrors()): ?> <div class="ui basic segment"> <?= $formView->renderErrorMessage() ?> </div> <?php endif ?> <div class="ui basic segment"> <?= $formView->getElement('email')->renderElement() ?> </div> <div class="ui basic segment"> <?= $formView->getSubmitElement()->renderElement() ?> </div>
3.2. Blocks & Rows
In the prior example we built our view by adding the email element directly to our view. Blocks and rows help us to automatically arrange our elements with ease.
Blocks
Blocks are directly added to your view and hold a unique ID which is needed to reference them later in your template. You can add as many block as you wish.
$block = new FormViewBlock('foo'); (new FormView())->addBlock($block);
Rows
Rows are added to your blocks and hold your elements. A row structures your elements in columns. There is no row limit for your blocks. Let's continue the blocks example:
$block = new FormViewBlock('foo'); $someElement = ... ; // some element $block->addRow( (new FormViewRow())->autoColumns($someElement) // takes up all columns ); (new FormView())->addBlock($block);
You can see that we are using autoColumns()
for setting our element. This means that the element will take as much space as is available for this row. For instance if we would have set second element for this row both elements would take 50% of the row's width.
// before // all auto columns $block->addRow( (new FormViewRow()) ->autoColumns($someElement) // takes up half of all columns ->autoColumns($someOtherElement) // takes up half of all columns ); // after
It is also possible to set a specific width for each element respectively to combine auto-width
with a specific-width
.
// before // two rows with mixed width specifications $block ->addRow( (new FormViewRow()) ->threeColumns($someElement) // takes up 3 columns ->autoColumns($someOtherElement) // takes everything what is left (13 columns) ) ->addRow( (new FormViewRow()) ->tenColumns($someElement) // takes up 10 columns ->sixColumns($someOtherElement) // takes up 6 columns ) ; // after
3.3. Elements
Most of the elements require a FormField
in order to be build. The following elements come delivered with your simplon\form release. You can always build your own elements which should inherit the abstract Element
class.
InputTextElement
This builds a single-line text field.
$element = new InputTextElement( new FormField('name') ); $element ->setLabel('Your name') ->setPlaceholder('Enter your name ...') ->setDescription('Name is needed so that we can address your properly') ; // attach to FormView ...
InputPasswordElement
This builds a single-line password field. This field inherits from InputTextElement
.
$element = new InputPasswordElement( new FormField('password') ); $element ->setLabel('Your password') ->setPlaceholder('Enter your password ...') ->setDescription('Needed so that you can login') ; // attach to FormView ...
InputHiddenElement
This builds a hidden field. This field inherits from InputTextElement
.
$element = new InputHiddenElement( new FormField('counter') ); // attach to FormView ...
TextareaElement
This builds a multi-line text field.
$element = new TextareaElement( new FormField('comment') ); $element ->setLabel('Your comment') ->setPlaceholder('Enter your comment ...') ->setRows(10) // determines rows-height; default is 4 ; // attach to FormView ...
CheckboxElement
We use checkbox elements for fields which offer one or more options to choose from - but in general only a few options. It requires at least one option. If any option has been selected you will receive an array of the selected options.
$options = (new OptionsMeta())->add('yes', 'I herewith confirm ...'); $confirmElement = new CheckboxElement( (new FormField('confirm'))->addMeta($options) ); // attach to FormView ... // [ ] I herwith confirm ...
Example for multiple values. We only need to add more options. Also, notice that it's sufficient to define a value for each our options. The value will be used for the label.
$options = (new OptionsMeta()) ->add('Magazines') ->add('Books') ->add('Newspapers') ; $confirmElement = new CheckboxElement( (new FormField('reading'))->addMeta($options) ); // attach to FormView ... // [ ] Magazines // [ ] Books // [ ] Newspapers
RadioElement
We use radio elements for fields which offer only a few options but where we require only one selection. Your selected option will be Note that it's sufficient to define a value for each our options. The value will be used for the label.
$options = (new OptionsMeta()) ->add('Magazines') ->add('Books') ->add('Newspapers') ; $confirmElement = new RadioElement( (new FormField('reading'))->addMeta($options) ); // attach to FormView ... // ( ) Magazines // ( ) Books // ( ) Newspapers
SubmitElement
This builds a submit button which can be added to your FormView
. It does not require any field but you may set a button label and add css classes.
$element = new SubmitElement('Save data', ['foo-class', 'bar-class']); // values are optional // attach to FormView ...
DropDownElement
We use drop-down elements for fields which offer one or more options to choose from. It requires at least one option. If any option has been selected you will receive it as a string within your request data. Multiple selections are passed on as string separated with commas.
Drop-down elements can either accept one- or multiple-selected options. We are also able to add new options on the fly. Further, we are able to filter through all options.
$options = (new OptionsMeta()) ->add('DE', 'Germany') ->add('FR', 'France') ->add('US', 'United States') ->add('...') ->add('...') ->add('...') ; $element = new DropDownElement( (new FormField('countries'))->addMeta($options) ); $element ->setLabel('City') ->setDescription('Search for a city') ->enableMultiple() // allows selection of multiple options ->enableSearchable() // lets user search over options ->enableAdditions() // lets user add new options ; // attach to FormView ...
TimeListElement
This element renders a drop-down with time options in the given minute interval. This field inherits from DropDownElement
.
$element = new TimeListElement( new FormField('time') ); $element ->setInterval(30) // build time options with 30 minutes interval ->enableNone() // add "none" option ; // attach to FormView // - None // - 00:00 // - 00:30 // - 01:00 // - 01:30 // - ... // - ... // - ...
DateListElement
This element renders a drop-down with date options starting from a given start date for a set number of days. This field inherits from DropDownElement
.
$element = new DateListElement( new FormField('date') ); $element ->setFormatOptionLabel('D, d.m.Y') // label for each option; e.g. Sat, 01.04.2017 ->setFormatOptionValue('Y-m-d') // value for each option; e.g. 2017-04-01 ->setStartingDate('2017-04-01') // set starting date; YYYY-MM-DD or unix time stamp ->setDays(7) // build date options for n days from given start date ->enableNone() // add "none" option ; // attach to FormView // - None // - Sat, 01.04.2017 // - Sun, 02.04.2017 // - Mon, 03.04.2017 // - Tues, 04.04.2017 // - ... // - ... // - ...
DateCalendarElement
We can also implement a proper calendar which is build on top of a calendar extension for Semantic-UI. Here are a couple of the look & feel of this extension. We are also making use of momentjs for rendering the actual dates while respecting locale information.
$element = new DateCalendarElement( new FormField('date') ); $calendar ->setLabel('Date') ->dateOnly() // only show dates ->setDateFormat('DD/MM/YYYY') // format of the selected date; e.g. 01/04/2017 // attach to FormView
Date/Time options: You can see that there is an option dateOnly()
which limits the calendar to let the user only select a date. By default the user is asked for a date/time combination. Related options are:
timeOnly()
monthOnly()
yearOnly()
Format options: Next to setDateFormat()
there are also the following format options: setTimeFormat()
and setDateTimeFormat()
.
Defining a range: It is also possible to two have two calendars being directly related so that the user can define a specific date range:
// // start date range // $startDateElement = (new DateCalendarElement(new FormField('startDate'))) ->setLabel('Start date') ->dateOnly() ->setDateFormat('DD/MM/YYYY') ; // // end date range // $endDateElement = new DateCalendarElement( new FormField('endDate'), $startDateElement // pass in related DateCalendarElement instance ); $endDateElement ->setLabel('End date') ->dateOnly() ->setDateFormat('DD/MM/YYYY') ;
DropDownApiElement
This element enables you to send a search request against a defined API and to display its results. This can work with any API since handling the response is up to you. Out of the box we support Algolia place search and Semantic-UI's API response handling.
$jsOptions = (new AlgoliaPlacesApiJs()) ->setType(AlgoliaPlacesApiJs::TYPE_CITY) ; $cityElement = new DropDownApiElement(new FormField('city'), $jsOptions); $cityElement ->enableMultiple() ->setLabel('City') ->setDescription('Search for a city') ;
ImageUploadElement
This element handles the client side of an image upload for you.
$imageElement = new ImageUploadElement(new FormField('urlImage'));
Following a snippet which shows an example of an implementation of an ImageUploadElement.
<div class="ui basic segment"> <h3>Image</h3> <?= $formView->getBlock('image')->render() ?> </div>
The uploaded image will be provided as dataURI
so it's up to you how you will process these data after the form has been successfully validated.
4. Block fields cloning
This feature gives the user the possibility to clone respectively remove field blocks dynamically. For instance, imagine you have to enter an unknown set of people addresses. In that case you have a set of core
fields which can be cloned by a simple click so that you can enter a new address straight away until you are done entering all addresses.
4.1. Building fields
$requestData = $_POST; // // required structure to apply stored data // each block represents a cloned field block // $storedData = [ 'clones' => [ 'address' => [ 'address' => 'Mr.', 'firstname' => 'Peter', 'lastname' => 'Foo', 'email' => 'peter.foo@bar.com', ] ] ]; // // define core clone fields // $cloneBlock = (new CloneFields('address')) ->add((new FormField('address'))->addMeta((new OptionsMeta())->add('Mr.')->add('Mrs.'))->addRule(new RequiredRule())) ->add((new FormField('firstname'))->addRule(new RequiredRule())) ->add((new FormField('lastname'))->addRule(new RequiredRule())) ->add((new FormField('email'))->addRule(new EmailRule())) ; // // add clone fields to our form fields // and apply stored data if available // $fields = (new FormFields()) ->add($cloneBlock) ->applyBuildData($storedData, $requestData) ; $validator = (new FormValidator($requestData))->addFields($fields)->validate(); if ($validator->hasBeenSubmitted()) { if ($validator->isValid()) { var_dump($fields->getAllData()); // expected result depending on how many blocks you cloned ... // results are wrapped in their clone field block ID // [ // 'clones' => [ // 'address' => [ // [ // 'address' => 'Mr.', // 'firstname' => 'Peter', // 'lastname' => 'Foo', // 'email' => 'peter.foo@bar.com', // ], // [ // ... // ] // ] // ] // ] } }
4.2 Building view
// // build view // $build = function (FormViewBlock $viewBlock, string $token) use ($fields) { $addressElement = (new DropDownElement($fields->get('address', $token)))->enableMultiple()->setLabel('Address'); $firstnameElement = (new InputTextElement($fields->get('firstname', $token)))->setLabel('First name'); $lastnameElement = (new InputTextElement($fields->get('lastname', $token)))->setLabel('Last name'); $emailElement = (new InputTextElement($fields->get('email', $token)))->setLabel('Email address')->setDescription('Required in order to send you a confirmation'); return $viewBlock ->addRow((new FormViewRow())->autoColumns($addressElement)) ->addRow((new FormViewRow())->autoColumns($firstnameElement)->autoColumns($lastnameElement)) ->addRow((new FormViewRow())->autoColumns($emailElement)) ; }; $addressBlocks = (new CloneFormViewBlock($cloneBlock))->build($build); $view = (new FormView()) ->setComponentDir('../../assets/vendor') ->addBlocks($addressBlocks) ; // // render view // https://github.com/fightbulc/simplon_phtml // echo (new Phtml())->render(__DIR__ . '/page.phtml', ['formView' => $view]);
4.3 Building templates
Page template
<?php /** * @var FormView $formView */ use Simplon\Form\View\FormView; ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0"> <title>simplon/form</title> <style type="text/css"> body { padding: 0; background: #fff; } </style> <?= $formView->renderAssets(FormView::ASSET_TYPE_CSS) ?> </head> <body> <div class="ui container"> <?= $formView->render(__DIR__ . '/form.phtml') ?> </div> <?= $formView->renderAssets(FormView::ASSET_TYPE_JS) ?> </body> </html>
Form template
/** * @var FormView $formView */ use Simplon\Form\View\FormView; ?> <?php if ($formView->hasErrors()): ?> <div class="ui basic segment"> <?= $formView->renderErrorMessage() ?> </div> <?php endif ?> <div class="ui basic segment"> <h3>Default</h3> <?= CloneFormViewBlock::render( $formView->getCloneBlocks('address'), function(FormViewBlock $block) { return $block->render(); } ) ?> </div> <div class="ui basic segment"> <?= $formView->getSubmitElement()->renderElement() ?> </div>
5. Settings
5.1 Field required/optional label
Fields can be marked being required
or optional
- so either one of the both states depending on your preference.
You will also have the possibility to override the default displayed words/characters e.g. to localise your form.
Toggle between required/optional
// // mark only optional fields // FormView::useOptionalLabel(true); // // mark only required fields // FormView::useOptionalLabel(false); // default value
Override label texts
// // override optional text // FormView::setOptionalLabel('opcional'); // translated to Spanish // // override required text // FormView::setRequiredLabel('*');
6. Examples
Coming soon