How to have the placeholder translated in an EntityType? - forms

I'm building a form which has an EntityType element, the problem I have is that I'm unable to have the placeholder translated.
Here is my code:
$builder
->add('Products', EntityType::class, [
'mapped' => false,
'expanded' => true,
'multiple' => false,
'required' => false,
'class' => Product::class,
'choices' => $options['step']->getProducts(),
'placeholder' => 'form.mat.alreadyOwned',
'label' => 'form.mat.alreadyOwned',
'translation_domain' => 'messages'
])
When I use the form.mat.alreadyOwnedtranslation as the label it works fine, but I would like to use it in the placeholder instead. What am I missing?
Looking forward to any tips or tricks that you have to offer!
[UPDATE]
As pointed out by #gp_sflover I'm not trying to replace the general placeholder, but the one for the empty value. This one only appears if you set required to false.

After some research and thought, the places where the placeholder is actually used are quite limited in number (as it should be). However, specific placeholder translation is not a special case (sadly).
For every choice in a ChoiceType a ChoiceView is added. Also for the placeholder a ChoiceView is added, that inherits the options of the form (which is a somewhat sensible choice for the ChoiceType), including the translation_domain parameter, which indicates that the choices shall be translated (all of them). There's also a reference in some twig template that specifically manages the translation in the twig bridge for non-expanded choice types. However, those don't open up a specific best practices answer on how to specifically handle translations for the placeholder in the ChoiceType.
For the EntityType, this doesn't change.
So there are a few approaches, some of which might be absolutely utility-free ...
translate the placeholder right there when building the form
Although this is conceptually not the most beautiful option, IMHO it's still the most practical one. Essentially, in Symfony 4 forms can receive dependencies in their constructor via auto-wiring, so injecting a TranslatorInterface will open up the ability to translate the placeholder with the requests locale (which is automatically set for the translator via event listener):
public function __construct(TranslatorInterface $translator) {
$this->translator = $translator;
}
and in your buildForm you can then use it to translate the placeholder
$builder
->add('Products', EntityType::class, [
'mapped' => false,
'expanded' => true,
'multiple' => false,
'required' => false,
'class' => Product::class,
'choices' => $options['step']->getProducts(),
'placeholder' => $this->translator->trans('form.mat.alreadyOwned'), // <-- change
'label' => 'form.mat.alreadyOwned',
'translation_domain' => 'messages'
])
not to withhold the other options, which in my opinion are almost all overkill...
set a choice_translation_domain for all entries, including placeholder
obviously, this can and probably will lead to problems, if there ever is an entity that whose choice label matches the key in the translator ... and it is not intended for translation. but it will translate the placeholder with the very same translation_domain ...
adapt the form rendering and check for the placeholder
this is problematic, since you have to assign the form theme/form rendering to all relevant forms. the placeholder does have a unique name ('placeholder', who would have thought) so it could very well be used to achieve that goal. However, setting a different translation domain could very much be challenging. (if you attempt this, it's a bit of a nuisance)
write your own entity type (optionally adding own form rendering)
theoretically, you could create your own EntityType and handle the placeholder properly there. like ... adding a translation domain to the choice view and sub form and what not. For inspiration/reference consult the ChoiceType, EntityType and DoctrineType (parent type).

Related

create a form for several entities symfony2.3 (best practice)

I want to create a form from several entities (article, category, adress, attributes, gallery) with custom fields (remove fields, customize css, ...),
what is the best practice with Symfony2 and forms
thank you.
Typically you want to you an embedded collection of forms to do this. An example shown bellow:
$builder->add('subject','text', array(
'required' => false,
));
$builder->add('body','textarea', array(
'required' => false,
));
$builder->add('files','collection', array(
'type' => new DocumentForm(),
'allow_add' => true,
'allow_delete' => true,
'label' => false,
));
This form binds to my message entity, however, you still have a collection type which relates to a different form that is attached to my file entity.
You want to embed entities and forms. You can find more information on this here:
http://symfony.com/doc/current/cookbook/form/form_collections.html

Disable some checkboxes in form

I was wondering if there is an easy way of how to disable one checkbox from modifying it by user (Symfony 2.1). I was trying something like this:
$builder->add('adminRoles', 'entity', array(
'property' => 'roleName',
'class' => 'MyBundle:Role',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('r')
->orderBy('r.roleName', 'ASC');
},
'disabled' => $this->disabledRoles,
'expanded' => true,
'multiple' => true
));
By $this->disabledRoles I meant an array of IDs of Role entities or entities themselves, but it seems that it just accepts boolean value which is applied for all entities (checkboxes). Thanks for your advice :-)
You will need to add a form listener in order to customize individual elements.
http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html
It might seem like a lot of work but it's easy enough once you work through the examples. You will end up passing disabledRoles to the listener and then setting the disabled flag accordingly.

Symfony2 how not to escape characters used in entity field property

I am using Symfony 2.1.8 and I have form with an entity which has many-to-one relation on it.
I use entity field for this member and i call it in the buildForm() as:
$builder->add('direction', 'entity', array(
'class' => 'CompanyBundle:Direction',
'property' => 'enTranslation.arrowedTitle',
'empty_value' => false,
'label' => 'Connection Direction',
'required' => false
));
enTranslation.arrowedTitle is a function that returns a string which including '⇒' (character set for right arrow)
when i call {{ form_widget(form.direction) }} i see the string as it is,(not the arrow but the &rArr) For displaying purposes, arrows must be showed, but i see &rArr in the field.
For simple string rendering, |rawfilter is used, but it does not work on widget. What should I do in order to display ⇒ instead of '&rArr ;' in the form? Thanks for any help.
You will have to create a form theme for at minimum the field type who's label includes that character.
Symfony/Twig escapes values by default for safety.
See this section of the documentation for more info:
http://symfony.com/doc/current/cookbook/form/form_customization.html#form-theming

How to use the ChoiceListInterface in Symfony 2?

I'd like to display a dynamic list of checkboxes in a form.
So far, I built a form embedding a static list of checkboxes, and I created a Tag entity for different values in different languages and populated the database. I'd like to replace the static checkboxes by a dynamic list based on the Tag entity.
The documentation says I should use the ChoiceListInterface. But it is really poorly documented. Would you have an example or a global logic explanation to help me ?
You can extend LazyChoiceList abstract class and implement loadChoiceList() method, create a service of it, inject it to the form and set it as choice_list option.
Finally, I used an entity field type :
->add('tags', 'entity', array(
'class' => 'bndMyBundle:Tag',
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('t')
->orderBy('t.en', 'ASC');
},
'expanded' => true,
'multiple' => true,
'property' => 'en',
))
Then, I just need to replace the 'en' value by the user's current locale to choose the right language.

Translate select options in Symfony2 class forms

I'm using a class form in Symfony2 Beta3 as follows:
namespace Partners\FrontendBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class ConfigForm extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('no_containers', 'choice', array('choices' => array(1 => 'yes', 0 => 'no')));
...
I want to translate the 'yes' and 'no' options, but I don't know how to use the translator here.
You can use the translation resources as usual. This worked for me:
$builder->add('sex', 'choice', array(
'choices' => array(
1 => 'profile.show.sex.male',
2 => 'profile.show.sex.female',
),
'required' => false,
'label' => 'profile.show.sex.label',
'translation_domain' => 'AcmeUserBundle'
));
And then add your translations to the Resources->translations directory of your Bundle.
Update from #CptSadface:
In symfony 2.7, using the choice_label argument, you can specify the translation domain like this:
'choice_label' => 'typeName',
'choice_translation_domain' => 'messages',
Without specifying the domain, options are not translated.
I searched a while to find an answer, but finally I found out how Symfony translates form content. The easiest way in your case seems to be to just add a translation for "yes" and "no" by adding a YAML or XLIFF translation file to your application (e.g. app/Resources/translations/messages.de.yml) or your bundle. This is described here:
http://symfony.com/doc/current/book/translation.html
The problem - in my opinion - is that you don't seem to be able to use custom translation keys. The guys from FOSUserBundle solve this (or a similar) problem with "Form Themes" (http://symfony.com/doc/2.0/cookbook/form/form_customization.html). Here are two significant lines of code to achieve the usage of the form element id as translation key:
https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/Resources/views/Registration/register_content.html.twig#L1 / https://github.com/FriendsOfSymfony/FOSUserBundle/blob/50ab4d8fdfd324c1e722cb982e685abdc111be0b/Resources/views/form.html.twig#L4
By adding a Form Theme you're able to modify pretty much everything of the forms in the templates - this seems to be the right way of doing this.
(Sorry, I had to split two of the links b/c I don't have enough reputation to post more than two links. Sad.)
In symfony 2.7, using the choice_label argument, you can specify the translation domain like this:
'choice_label' => 'typeName',
'choice_translation_domain' => 'messages',
Without specifying the domain, options are not translated.
CptSadface's answer was what helped me with translating my entity choices.
$builder
->add(
'authorizationRoles',
null,
[
'label' => 'app.user.fields.authorization_roles',
'multiple' => true,
'choice_label' => 'name', // entity field storing your translation key
'choice_translation_domain' => 'messages',
]
);