I built a registration form in Symfony. I am asking for date of birth to my user. I'd like to know how I can display months in French (or other languages). At the moment they are displayed in English. I posted code on UserType.php. I am thinking maybe I have to add something in it but I have no clue.
How can I display months in French ?
Thank you.
UserType.php
<?php
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\LanguageType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
class UserType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('gender', ChoiceType::class, [
'choices' => [
'Je suis ...' => '',
'un homme' => 'male',
'une femme' =>'female',
'non-binaire' => 'non-binary'
]
])
->add('lastname')
->add('firstname')
->add('birthdate', BirthdayType::class, [
'placeholder' => [
'year' => 'Année', 'month' => 'Mois', 'day' => 'Jour',
],
])
->add('occupation')
->add('nationality', CountryType::class, [
'placeholder' => 'Choisis un pays',
])
->add('nativelanguage', LanguageType::class, [
'placeholder' => 'Choisis ta langue maternelle',
])
->add('wishedlanguages', LanguageType::class, [
'placeholder' => 'Choisis une langue étrangère',
])
->add('email')
->add('password', PasswordType::class, [
'mapped' => false
])
->add('password', RepeatedType::class, [
'type' => PasswordType::class,
'invalid_message' => 'Les deux mots de passe doivent être identiques.',
'options' => ['attr' => ['class' => 'password-field']],
'required' => true,
'first_options' => ['label' => 'Password'],
'second_options' => ['label' => 'Repeat Password'],
])
->add('roles', CheckboxType::class, [
'label' => 'Je m\'inscris uniquement en tant qu\'organisateur.',
'required' => false,
'compound' => true,
])
->get('roles')
->addModelTransformer(new CallbackTransformer(
function ($arrayAsBool) {
return in_array("ROLE_ADMIN", $arrayAsBool);
},
function ($boolAsArray) {
return $boolAsArray ? ["ROLE_ADMIN"] : ["ROLE_USER"];
}))
->add('Subcription', SubmitType::class);
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
The BirthdayType supports choice_translation_domain, set this to true.
->add('birthdate', BirthdayType::class, [
'placeholder' => [
'year' => 'Année', 'month' => 'Mois', 'day' => 'Jour',
],
'choice_translation_domain' => true
])
Update your defaults to set the translation domain name.
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => User::class,
'translation_domain' => 'forms' // Call it what you like
]);
}
Then create a translation file, eg: translations/forms.fr.yaml. This filename is referencing the translation_domain above.
# translations/forms.fr.yaml
Jan: Janvier
Feb: Février
Mar: Mars
...
...
The language locale fr for example, is set in the users request i believe, so you can have as many language translations as you would like. So forms.de.yaml, forms.es.yaml etc.. and wherever the user is coming from, if the translation matches it will use it.
Related
I want to add an extra fiel to a form, in Symfony, but it won't accept it if it's not bound to an entity attribute.
If someone knows what I can do to fix it, many thanks in advance !
Here is the formtype, I'm trying to add the "extra" field :
<?php
namespace App\Form;
use App\Entity\Dossier;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class InscriptionBCType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('extra', TextType::class, [
'label' => 'Les besoins qui motivent votre demande (soyez exhaustif)',
'required' => false,
])
->add('Nom')
->add('Prenom')
->add('Mail')
->add('civilite', ChoiceType::class, [
'choices' => [
'Monsieur' => "Monsieur",
'Madame' => "Madame",
],
]) ->add('telephone')
->add('adresse')
->add('code_postal')
->add('ville')
->add('projet', TextType::class, [
'label' => 'votre projet entrepreneurial (SI VOUS EN AVEZ UN)(FACULTATIF)',
'required' => false,
])
->add('besoin', TextType::class, [
'label' => 'Les besoins qui motivent votre demande (soyez exhaustif)',
'required' => false,
])
->add('budgetCPF', TextType::class, [
'label' => 'Votre budget CPF mobilisable',
'required' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Dossier::class,
]);
}
}
And I get this error :
Can't get a way to read the property "extra" in class "App\Entity\Dossier".
I know I already answered the question in the comments but not everyone reads them this is why I am posting it as an answer,if you want a field to be ignored you have to use mapped for example:
add("extra"=> 'file', array("mapped"=>false))
When i register with my form(1) the roles the user select isn't entered in the bdd instead it enter just [] i couldn't get it enter either ROLE_USER or ROLE_ADVERTISER or both in array in the bdd, roles is a longtext in,
Here is my Form builder:
class RegistrationFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('agreeTerms', CheckboxType::class, [
'mapped' => false,
'constraints' => [
new IsTrue([
'message' => 'You should agree to our terms.',
]),
],
])
->add('plainPassword', PasswordType::class, [
// instead of being set onto the object directly,
// this is read and encoded in the controller
'mapped' => false,
'constraints' => [
new NotBlank([
'message' => 'Please enter a password',
]),
new Length([
'min' => 6,
'minMessage' => 'Your password should be at least {{ limit }} characters',
// max length allowed by Symfony for security reasons
'max' => 4096,
]),
],
])
->add('roles', ChoiceType::class, [
'required' => true,
'multiple' => false,
'expanded' => false,
'choices' => [
'ROLE_USER' => 'ROLE_USER',
'ROLE_ADVERTISER' => 'ROLE_ADVERTISER',
],
]);
$builder->get('roles')
->addModelTransformer(new CallbackTransformer(
function ($rolesArray) {
// transform the array to a string
return count($rolesArray)? $rolesArray[0]: null;
},
function ($rolesString) {
// transform the string back to an array
return [$rolesString];
}
));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
I would like to validate a input password field in a form based in the value of checkbox. If the value is TRUE the password fields should be NOTBlank and Equal first to second. This what i have so far:
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
class UsuarioFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nombre',null,[
'required' => true,
'constraints'=> [
new NotBlank([
'message' => 'Escriba el nombre por favor',
]),
]
])
->add('apellido',null,[
'required' => true,
'constraints'=> [
new NotBlank([
'message' => 'Escriba el apellido por favor',
]),
]
])
->add('user_name',null,[
'required' => true,
'empty_data' => '',
'constraints'=> [
new NotBlank([
'message' => 'Escriba el nombre de usuario por favor',
]),
]
])
->add('active', CheckboxType::class, [
'required' => false
])
->add('email',EmailType::class,[
'constraints' => [
new Email([
'mode'=> 'html5',
'message' => 'El correo electrónico {{ value }} no es un correo electrónico válido',
]),
]
])
->add('plainPassword', RepeatedType::class, [
'type' => PasswordType::class,
'invalid_message' => 'Los campos de contraseña deben ser iguales',
'mapped' => false,
'required' => false,
'constraints' => [
new Length([
'min' => 6,
'minMessage' => 'Your password should be at least {{ limit }} characters',
// max length allowed by Symfony for security reasons
'max' => 4096,
]),
],
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
'constraints' => [
new Callback([$this, 'validate']),
],
]);
}
public function validate($data, ExecutionContextInterface $context): void
{
if ($data['chk_passUpdate']){
if (trim($data['plainPassword']['first']) == '' ) {
$context->buildViolation('El campo de contraseña no puede estar en blanco')
->atPath('plainPassword')
->addViolation();
}
if ($data['plainPassword']['first'] != $data['plainPassword']['second'] ) {
$context->buildViolation('Los campos de contraseña deben ser iguales')
->atPath('plainPassword')
->addViolation();
}
}
}
}
This code throw a Exception:
Argument 1 passed to App\Form\UsuarioFormType::validate() must be of the type array, object given, called in C:\Csi\CsiWorkspace\SynfonyTest\SymfonyTest\vendor\symfony\validator\Constraints\CallbackValidator.php on line 46
After a week i found the best solution is to use validation groups.
So my code will be like this:
namespace App\Form;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\FormInterface;
class UsuarioFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nombre',null,[
'required' => true,
'constraints'=> [
new NotBlank([
'message' => 'Escriba el nombre por favor',
]),
]
])
->add('apellido',null,[
'required' => true,
'constraints'=> [
new NotBlank([
'message' => 'Escriba el apellido por favor',
]),
]
])
->add('user_name',null,[
'required' => true,
'empty_data' => '',
'constraints'=> [
new NotBlank([
'message' => 'Escriba el nombre de usuario por favor',
]),
]
])
->add('active', CheckboxType::class, [
'required' => false
])
->add('password_update', CheckboxType::class, [
'required' => false,
'mapped' => false
])
->add('email',EmailType::class,[
'constraints' => [
new Email([
'mode'=> 'html5',
'message' => 'El correo electrónico {{ value }} no es un correo electrónico válido',
]),
]
])
->add('plainPassword', RepeatedType::class, [
'type' => PasswordType::class,
'invalid_message' => 'Los campos de contraseña deben ser iguales',
'mapped' => false,
'required' => false,
'constraints' => [
new Length([
'min' => 6,
'minMessage' => 'Your password should be at least {{ limit }} characters',
// max length allowed by Symfony for security reasons
'max' => 4096,
]),
new NotBlank([
'message' => 'Escriba su contraseña',
'groups' => 'password_update'
]),
],
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
'validation_groups' => function(FormInterface $form){
if ($form['password_update']->getData()){
return array('Default', 'password_update');
}else{
return array('Default');
}
}
]);
}
}
In that way, when the checkbox is on, the form will validate 2 groups (default and password_udpate). If its off only the default group will be validated.
Hope this help somebody some day.
I have a form without an entity and it is constructed like in the documentation of Symfony:
$form = $this->createFormBuilder(['message' => 'Standard message'])
->add('....', EntityType::class, [
'class' => '....',
'choice_label' => 'name',
])
->add('.....', DateType::class, [
'widget' => 'single_text',
'html5' => false,
'attr' => ['class' => 'js-datepicker'],
])
->add('....', DateType::class, [
'widget' => 'single_text',
'html5' => false,
'attr' => ['class' => 'js-datepicker'],
])
->add('Submit', SubmitType::class)
->getForm();
However, is there any possibility to use a Form Type class and retrieve data back in the controller? My controllers are becoming pretty large now because there is a lot of form code in there. When I try to shift the code into a separate form type class, it seems like the form is processed but when I try to call $form->getData() inside my controller it is empty. I use the following code:
$form = $this->createForm(MyFormType::class);
$form->handleRequest($request);
if($request->isMethod('POST')){
print_r($form->getData()); // Empty?
die();
}
My form class is as following:
namespace AppBundle\Form;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
class MyFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('....', DateType::class, [
'widget' => 'single_text',
'html5' => false,
'attr' => ['class' => 'js-datepicker'],
])
->add('....', DateType::class, [
'widget' => 'single_text',
'html5' => false,
'attr' => ['class' => 'js-datepicker'],
])
->add('....', EntityType::class, [
'class' => '....',
'choice_label' => 'name',
])
->add('Submit', SubmitType::class);
}
}
The alternative is to put the code into a separate service but I think it is cleaner to use a form type.
My collection is made of this type
<?php
namespace Gustaw\AdminBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class AttributeValueType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('value')
->add('translations', 'a2lix_translations');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Gustaw\AdminBundle\Entity\AttributeValue',
'label' => false,
));
}
public function getName()
{
return 'attribute_value_type';
}
}
And this is my form
public function configureFormFields(FormMapper $formMapper) {
$formMapper->with('General')
->add('name', null, array('required' => true))
->add('translations', 'a2lix_translations', array(
'by_reference' => false,
'fields' => array(
'name' => array()
)
))
->add('custom', null, array(
'required' => false,
))
->add('category', 'entity', array(
'required' => true,
'class' => 'GustawAdminBundle:Category',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.root', 'ASC')
->addOrderBy('c.lft', 'ASC');
},))
->end()
->with('Values')
//->add('values', 'sonata_type_collection')
->add('notcustomvalues', 'collection', array(
'type' => new AttributeValueType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => false,
'required' => false,
))
->end();
}
Problem is when adding new elements to collection. Each single AttributeValueType gets a label "__name__label__ *" when I don't want to have any label for this field as I set it to false.
I tried setting "prototype_name" hoping it will change something just to make it worse.
The only ideas that came to my mind are:
1st - create custom theme without label just for this one collection
2nd - edit base.js in SonataAdminBundle
2nd obviously is not really good option so I am left just with the first one.
Question is: Are there any other options I have?
Try to add: 'options' => array(label => 'Some Label');
Like this:
->add('notcustomvalues', 'collection', array(
'type' => new AttributeValueType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => false,
'required' => false,
'options' => array(
'label' => 'Some Label'
),
))