Form construction
Forms can consist of multiple parts with each part utilizing almost everything you can imagine having on a form. We deliver most of the parts out of the box but also enable developers to come up with their own. These form elements may also have accessories, which are injectable templates that can be rendered (directly or conditionally) alongside them. In other words, a form part is a block within a template while an accessory shares the same structure but can be utilized across multiple parts.
Save services
- Class: \Hyva\Checkout\Model\Form\AbstractEntityFormSaveService
Save Services are responsible for writing data to a specific source such as the database. Every form is obligated to include a Save Service.
Modifiers
- Interface: \Hyva\Checkout\Model\Form\EntityFormModifierInterface
Forms can receive various modifications based on specific hooks triggered during both the initialization and submit handling processes.
Modifiers necessitate a single apply()
method where modification callbacks can be registered using the registerModificationListener()
method.
Additionally, existing modifiers can be removed using the unregisterModificationListener()
method. Hooks are dispatched
using the dispatchModificationHook()
method.
Elements
- Class: \Hyva\Checkout\Model\Form\AbstractEntityFormElement
Forms mainly consist of elements. Elements are nothing more than layout blocks with a template that automatically binds to an element object. The element object can consist of a number of basic classes that are provided with the checkout or your own custom injected objects. Elements cannot hold values themselves.
Elements don't inherently know how to be rendered. Therefore, we've developed a specific rendering mechanism that can be controlled via regular Layout XML. Check out the rendering page for comprehensive details on all possibilities.
Clickable (abstract)
- Class: \Hyva\Checkout\Model\Form\EntityFormElement\Clickable
As the name partly suggests, a clickable is an abstraction layer for HTML elements that are clickable.
This doesn't necessarily have to be a <button>
element.
Button
- Class: \Hyva\Checkout\Model\Form\EntityFormElement\Button
Compared to a clickable, a button is indeed of the type button
by default but is also derived from the abstract Clickable.
A button can simply function as a regular button, but can also serve as an abstraction layer, for example, for a submit button.
<?php
$form->createElement(Hyva\Checkout\Model\Form\EntityFormElement\Button::class, [
'data' => [
'label' => 'Open modal'
]
])
Submit
- Class: \Hyva\Checkout\Model\Form\EntityFormElement\Submit
A submit button is again a derivation of a regular button. A submit button requires more specifications,
such as a default "Submit" label, a different element type, and contains its own so-called layoutAlias
to be able to
designate a template very specifically for this type of form element.
<?php
$form->createElement(Hyva\Checkout\Model\Form\EntityFormElement\Submit::class, [
'data' => [
'label' => 'Submit form'
]
])
URL
- Class: \Hyva\Checkout\Model\Form\EntityFormElement\Url
Similar to the submit button, a URL element also possesses its own layoutAlias
, denoted by the url
alias, enabling
the application of a specific template. In addition to the alias, the URL element can contain a value accessed through
the src
attribute, which can be set using setValue(string $url)
respectively.
<?php
$form->createElement(Hyva\Checkout\Model\Form\EntityFormElement\Url::class, [
'data' => [
'url' => 'https://hyva.io',
'label' => 'Hyvä Themes'
]
])
Fields
- Class: \Hyva\Checkout\Model\Form\EntityField\AbstractEntityField
Fields are an extension of elements specifically designed to hold values. Fields are more elaborate elements and contain a more specific set of capabilities.
By default, fields automatically fallback onto the text template if no specific template was defined. Each field can be fully customized according to its needs by assigning its own distinctive template via regular Layout XML. Check out the rendering page for comprehensive details on all possibilities.
Input
- Class: \Hyva\Checkout\Model\Form\EntityField\AbstractEntityField
The input field element is a child of the abstraction layer and should be used in most common cases where a customer
needs to fill in a regular text value. The input field can be used for multiple purposes, where a form modifier can
adjust the input type if it needs to be changed to email
or tel
, for example.
Factories
Form elements or fields can be created dynamically by invoking methods such as $form->createField()
or $form->createElement()
.
These methods utilize designated factories to seamlessly generate and provide the appropriate objects.
By default, when utilizing the Hyva\Checkout\Model\Form\AbstractEntityForm
, fields are generated using the
Hyva\Checkout\Model\Form\EntityFormFieldFactory
, while elements are instantiated through Hyva\Checkout\Model\Form\EntityFormFactory
.
These factories are injected into the constructor via their predetermined names fields
and elements
.
Furthermore, custom factories can be injected into your form object, empowering you to fulfill diverse requirements
simply by defining and subsequently accessing them through $form->getFactoryFor('my_custom_factory')
.
While the default field and element factories suffice for most scenarios, this flexibility allows for tailored solutions when necessary.
<!-- Inject global custom factory. -->
<type name="Hyva\Checkout\Model\Form\AbstractEntityForm">
<arguments>
<argument name="factories" xsi:type="array">
<item name="my_example_factory" sortOrder="30" xsi:type="object">My\Example\Model\Form\EntityFormFactory\MyExampleFactory</item>
</argument>
</arguments>
</type>
Elements factory
This factory assumes the role of generating form element objects. To instruct the create()
method on what to produce,
it's imperative to specify requirements. For an element, this entails providing a $name
such as "button" or "promotional_banner".
These mappings are defined within etc/frontend/di.xml
:
<type name="Hyva\Checkout\Model\Form\EntityFormFactory">
<arguments>
<argument name="elements" xsi:type="array">
<item name="promotional_banner" xsi:type="string">My\Example\Model\Form\EntityFormElement\PromotionalBanner</item>
</argument>
</arguments>
</type>
Direct object assignment
Mapping elements via di.xml is preferable for enhancing the reusability of elements across multiple forms. However, you
also have the option to directly assign the object to the method, like $form->createElement(PromotionalBanner::class)
.
However, this necessitates some additional options where the default element renderer will search for either a layout alias or the ID data value. As an extension, this can be accomplished simply through the following two examples.
-
By layout alias:
<?php namespace My\Example\Model\HyvaCheckout\Form\EntityFormElement; class PromotionalBanner extends \Hyva\Checkout\Model\Form\AbstractEntityFormElement { public function getLayoutAlias() { // The renderer will search for "{form_namespace}.promotional_banner" or "promotional_banner". return 'promotional_banner'; } }
-
By element ID:
More details about rendering can be found here
Fields factory
The field factory operates on the fundamental principle of constructing elements within a given field. While its core
concept remains constant, slight variations emerge in the parameters required for the create()
method and the mapping
of distinct field objects to the factory.
A distinction lies in the resolution process for determining the appropriate object. This parallels the method used to identify the correct render template, as detailed in the documentation on rendering fields. A fallback mechanism is employed to determine which object should be utilized. In cases where injecting a different object for a specific form is feasible, this mechanism ensures continuity by retaining the globally assigned object for all other forms.
Level | Alias | Since |
---|---|---|
6 | {form_namespace}.{field_name}.{input_type} | 1.1.0 |
5 | {form_namespace}.{field_name} | 1.1.0 |
4 | {field_name}.{input_type} | 1.1.0 |
3 | {field_name} | 1.1.0 |
2 | {form_namespace}.{input_type} | 1.1.0 |
1 | {input_type} | 1.1.0 |
What is the reason for not having a fallback for elements?
Elements can possess an infinite array of distinctive name options and do not necessitate a specific type. Conversely, types adhere to a predetermined range of HTML input types for selection. Consequently, the capacity to modify objects without the need to alter all instances is only essential for fields.
These mappings are defined within etc/frontend/di.xml
:
<type name="Hyva\Checkout\Model\Form\EntityFormFactory">
<arguments>
<argument name="elements" xsi:type="array">
<!-- {field_name} -->
<item name="delivery_date" xsi:type="string">My\Example\Model\Form\EntityFormField\DeliveryDate</item>
<!-- {form_namespace}.{field_name} -->
<item name="example_form.delivery_date" xsi:type="string">My\Example\Model\Form\EntityFormField\ExampleForm\DeliveryDate</item>
</argument>
</arguments>
</type>
System elements
Hyvä Checkout comes with multiple fields and elements out of the box where some are specifically aimed to handle EAV attributes.
Name | Factory | Abstraction | HTML Element | Input Type | EAV |
---|---|---|---|---|---|
submit | Element | Button | Button | N/A | No |
id | Field | AbstractEntityField | Input | Hidden | No |
save | Field | AbstractEntityField | Input | Checkbox | No |
telephone | Field | EavAttributeField | Input | Tel | Yes |
street | Field | EavAttributeField | Input | Text | Yes |
region | Field | EavAttributeField | Input, Select | Text, Select | Yes |
country_id | Field | EavAttributeField | Select | Select | Yes |
postcode | Field | EavAttributeField | Input | Text | Yes |
prefix | Field | EavAttributeField | Select | N/A | Yes |
gender | Field | EavAttributeField | Select | N/A | Yes |
We are exploring the option of renaming the EAV attributes for addresses to include an eav_
prefix in their names, particularly where the current names are too general. We aim to accomplish this without causing any backward incompatible changes, most likely by introducing a dedicated EAV field factory.