Reputation: 188
I have a Symfony2 form where a user can enter an address which is now in a fixed format and since we want to offer our software internationally I am looking for the best way to implement this in SF.
Instead of making one generic address type
we'd like to localize the forms with one generic format as fallback for unsupported locales.
I want to separate layout and localization (order, grouping, labels, translations, mandatory and optional fields) from the processing (PHP/SF) of the forms and the actual rendering (TWIG).
What I came up was this: create a address
form type from a database model which contains all possible fields. Render this form type in twig automatically by calling form_widget(form)
or by rendering individual fields when needed. And lastly; define the "layout" of a form in some kind of config format (YML, array, whatever) and extend the default TWIG form rendering to itterate through the form elements defined in said config.
For example the address config for The Netherlands and the US would be:
- NL-nl
- [firstname, infix, lastname]
- [street1, number]
- [postcode, city]
- EN-us
- [fullname]
- [street1]
- [street2]
- [city, state]
- [zip]
Later we'll add localized labels, classes, optional and mandatory fields, etc to this configuration.
For now our big question is: where to put this config? Use a simple array in the finishView
class? Put the config in a YML file that's parsed by the form types that need a localized form layout?
Any information from people that encountered this problem would be appreciated.
Upvotes: 4
Views: 716
Reputation: 9575
Later we'll add localized labels, classes, optional and mandatory fields, etc to this configuration.
The localized labels is automatic process where they can be translated and converted based on the user's locale. The mandatory fields could be resolved using constraints.
where to put this config?
In my opinion this should be made directly into the entity and form type:
You can create an LocaleAddressType
and to add these fields depending on current "locale" value, but first, you needs to have an Entity with all possible fields related to "address" approach.
LocaleAddress
entity:// src/AppBundle/Entity/LocaleAddress.php
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Table()
* @ORM\Entity()
*/
class LocaleAddress
{
/**
* @var string
*
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @Assert\NotBlank(groups={"nl-NL", ...})
* @ORM\Column(type="string", nullable=true)
*/
private $firstName;
// ...
}
Includes all distinct fields for all possible locales and settings these with nullable=true
. Plus, use the NotBlank
constraint and groups
option to validate required fields per locale.
# AppBundle/Resources/config/locale_address_form.yml
address_form:
nl-NL:
- [firstname, infix, lastname]
- [street1, number]
- [postcode, city]
en-US:
- [fullname]
- [street1]
- [street2]
- [city, state]
- [zip]
LocaleAddressType
adds some fields depending on the locale
option, by default it is Locale::getDefault()
// src/AppBundle/Form/Type/LocaleAddressType.php
class LocaleAddressType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$config = $this->loadLocaleFormConfig($options['locale']);
foreach ($config as $fields) {
foreach (fields as $field) {
$builder->add($field);
}
}
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['config'] = $this->loadLocaleFormConfig($options['locale']);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\LocaleAddress',
'locale', \Locale::getDefault(),
]);
// force that validation groups will equal to configured locale.
$resolver->setNormalizer('validation_groups', function (Options $options) {
return [$options['locale']];
});
$resolver->setAllowedTypes('locale', ['string']);
// pending validate the custom locale value.
}
private function loadLocaleFormConfig($locale)
{
$config = Yaml::parse(file_get_contents('path/to/locale_address_form.yml'));
return $config['address_form'][$locale];
}
}
Note: On submit that fields are validated in correspondence with the locale
value.
Register the form type:
# app/config/services.yml
services:
app.form.locale_address:
class: AppBundle\Form\Type\LocaleAddressType
tags:
- { name: form.type }
Now, you can use this form type in other forms with localeAddress
field associacion.
$build->add('localeAddress', LocaleAddressType::class);
When the locale in your application is changed \Locale::setDefault
this will affects the form fields to display.
I want to separate layout and localization (order, grouping, labels, translations, mandatory and optional fields) from the processing (PHP/SF) of the forms and the actual rendering (TWIG).
{% block locale_address_widget %}
{% for fields in config %}
<div class="row">
{% set n = 12 // fields|length %}
{% for field in fields %}
<div class="col-md-{{ n }}">
{{ form_row(form[field]) }}
</div>
{% endfor %}
</div>
{% endfor %}
{% endblock %}
The code is Symfony3-based.
Upvotes: 3
Reputation: 96
There are many options:
Upvotes: 0