Introduction
This article explains how you can define fields in model editing form.
Throughout the article we will be refering to XCExample\ModelEditingAdvanced module as an example. It creates target=example_product_edit_advanced
page in admin area, where you can play with form fields.
Field definition
Fields are defined in \XLite\View\FormModel\AFormModel::defineFields()
method. This method must return an array of the following structure:
[
'section_name' => [
'field_name' => [
// field settings
],
'another_field_name' => [
// another field settings
],
],
'second_section_name' => [
// definition of fields in this section
]
]
Section names are provided by defineSections()
method. Please refer to Form sections article to learn more about sections.
Here is an example of simple field definition:
self::SECTION_DEFAULT => [
'full_description' => [
'label' => static::t('Description'),
'type' => 'XLite\View\FormModel\Type\TextareaAdvancedType',
'position' => 400,
],
]
self::SECTION_DEFAULT
is the name of the section ('default');full_description
is the name of the field;- 'label', 'type' and 'position' are all settings of this
full_description
field:- 'label' defines the wording before the field
- 'type' defines widget that will be used for input field of the field. If this parameter is omitted, we will use regular text input, which is defined by
\Symfony\Component\Form\Extension\Core\Type\TextType
class. In our particular case, we define form field type as\XLite\View\FormModel\Type\TextareaAdvancedType
which is an input with HTML editor; - 'position' defines where the field will be located. The greater the value the lower it will sit.
- 'type' defines widget that will be used for input field of the field. If this parameter is omitted, we will use regular text input, which is defined by
- 'label' defines the wording before the field
There can be more settings except of three basic ones above. Let us have a look atdefineFields()
method from 'XCExample\ModelEditingAdvanced' module:
protected function defineFields()
{
$skuMaxLength = \XLite\Core\Database::getRepo('XLite\Model\Product')->getFieldInfo('sku', 'length');
$nameMaxLength = \XLite\Core\Database::getRepo('XLite\Model\ProductTranslation')->getFieldInfo('name', 'length');
$currency = \XLite::getInstance()->getCurrency();
$currencySymbol = $currency->getCurrencySymbol(false);
$schema = [
self::SECTION_DEFAULT => [
'generate_sku' => [
'label' => static::t('Generate SKU'),
'help' => static::t('You can generate SKU'),
'type' => 'XLite\View\FormModel\Type\SwitcherType',
'position' => 100,
],
'sku' => [
'label' => static::t('SKU'),
'constraints' => [
'XLite\Core\Validator\Constraints\MaxLength' => [
'length' => $skuMaxLength,
'message' =>
static::t('SKU length must be less then {{length}}', ['length' => $skuMaxLength]),
],
],
'enable_when' => [
'default' => [
'generate_sku' => '',
],
],
'position' => 200,
],
'name' => [
'label' => static::t('Product name'),
'description' => static::t('Product name'),
'required' => true,
'constraints' => [
'Symfony\Component\Validator\Constraints\NotBlank' => [
'message' => static::t('This field is required'),
],
'XLite\Core\Validator\Constraints\MaxLength' => [
'length' => $nameMaxLength,
'message' =>
static::t('Name length must be less then {{length}}', ['length' => $nameMaxLength]),
],
],
'position' => 300,
],
'full_description' => [
'label' => static::t('Description'),
'type' => 'XLite\View\FormModel\Type\TextareaAdvancedType',
'position' => 400,
],
],
'price' => [
'price' => [
'label' => static::t('Price'),
'type' => 'XLite\View\FormModel\Type\SymbolType',
'symbol' => $currencySymbol,
'pattern' => [
'alias' => 'xcdecimal',
'prefix' => '',
'rightAlign' => false,
'digits' => $currency->getE(),
],
'constraints' => [
'Symfony\Component\Validator\Constraints\GreaterThanOrEqual' => [
'value' => 0,
'message' => static::t('Minimum value is X', ['value' => 0]),
],
],
'position' => 100,
],
'inventory_tracking' => [
'label' => static::t('Inventory tracking is'),
'type' => 'XLite\View\FormModel\Type\Base\CompositeType',
'fields' => [
'inventory_tracking' => [
'type' => 'XLite\View\FormModel\Type\SwitcherType',
'position' => 100,
],
'quantity' => [
'label' => static::t('Quantity in stock'),
'type' => 'XLite\View\FormModel\Type\PatternType',
'pattern' => [
'alias' => 'integer',
'rightAlign' => false,
],
'constraints' => [
'XLite\Module\XCExample\ModelEditingAdvanced\Core\Validator\Constraints\Even' => [
'message' => static::t('Only even value allowed'),
],
],
'show_when' => [
'price' => [
'inventory_tracking' => [
'inventory_tracking' => '1',
],
],
],
'position' => 200,
],
],
'position' => 200,
],
],
];
return $schema;
}
We can see here following settings we have not met before:
- 'help' setting in 'generate_sku' field. This setting defines a text for question mark icon near the field:
- 'constraints' setting defines certain restrictions for the field's value. There are different constraints in
defineFields()
method shown above:- max length constraint
XLite\Core\Validator\Constraints\MaxLength
;- non-blank value constraint
Symfony\Component\Validator\Constraints\NotBlank
; - constraint of value being equal or greater than some number
Symfony\Component\Validator\Constraints\GreaterThanOrEqual
; - even number constraint
XLite\Module\XCExample\ModelEditingAdvanced\Core\Validator\Constraints\Even
. Learn more about constraints in the dedicated article.
- non-blank value constraint
- max length constraint
- 'enable_when' setting defines a condition when the field is available for editing. It looks as follows in our code:This condition means that 'sku' field can be edited only if 'generate_sku' switcher in 'default' section is turned off.
'sku' => [
// ...
'enable_when' => [
'default' => [
'generate_sku' => '',
],
],
// ...
] - 'show_when' setting is similar to 'enable_when' one above, but it defines a condition when the field is displayed. Here is an example from the code above:Such code means that 'quantity' field will be shown only when 'inventory_tracking' switcher in 'inventory_tracking' sub-section of 'price' section is turned on.
'quantity' => [
// ...
'show_when' => [
'price' => [
'inventory_tracking' => [
'inventory_tracking' => '1',
],
],
],
// ...
], - 'required' setting defines a field that must be filled in, it cannot be blank.
- You can see other settings such as 'symbol' or 'pattern' in field definition. These parameters are used by the widget specified in 'type' setting (in this case,
XLite\View\FormModel\Type\SymbolType
class). If we have a look atconfigureOptions()
method of this class:We can see that these options ('symbol' and 'pattern') are indeed options of this widget. You can always check custom options of any given widget in thispublic function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
[
'left_symbol' => '',
'right_symbol' => '',
'symbol' => '',
'pattern' => '',
'compound' => false,
'transformToFloat' => true
]
);
}configureOptions()
method. Also, all global field options are listed in\XLite\View\FormModel\Type\Base\FormTypeExtension::configureOptions()
method.
Horizontal fields
Sometimes you want to display several fields on the same level. Examples:
Product page:
admin.php?target=example_product_edit_advanced
page in 'XCExample\ModelEditingAdvanced' module (you should expand 'Price' section):
To define such horizontal fields you must set XLite\View\FormModel\Type\Base\CompositeType
as 'type' setting and define subfields as value of 'fields' option. Child field definition will be the same as regular field definition.
// ...
'inventory_tracking' => [
'label' => static::t('Inventory tracking is'),
'description' => $inventoryTrackingDescription,
'type' => 'XLite\View\FormModel\Type\Base\CompositeType',
'fields' => [
'inventory_tracking' => [
'type' => 'XLite\View\FormModel\Type\SwitcherType',
'position' => 100,
],
'quantity' => [
'label' => static::t('Quantity in stock'),
'type' => 'XLite\View\FormModel\Type\PatternType',
'pattern' => [
'alias' => 'integer',
'rightAlign' => false,
],
'show_when' => [
'prices_and_inventory' => [
'inventory_tracking' => [
'inventory_tracking' => '1',
],
],
],
'position' => 200,
],
],
'position' => 400,
],
// ...
The first field in 'fields' section should not have 'label' setting as it will inherit it from the composite field. If you specify 'label' setting in the first field, it will be disregarded.