I have a form builder set to create an user info form:
$form = $this->createFormBuilder($userSettings)
->add('newName', TextType::class, array(
'required' => false,
'label' => "Change UserName",
'attr' => array(
'placeholder' => $userData[0]->getUsername()
)
))
->add('newMail', TextType::class, array(
'required' => false,
'label' => "Change Email",
'attr' => array(
'placeholder' => $userData[0]->getEmail()
)
))
->add('newPassword', PasswordType::class, array(
'required' => false,
'label' => "Change Password"
))
->add('currentPassword', PasswordType::class, array(
'label' => "Current Password"
))
->add('save', SubmitType::class, array('label' => 'Update Information!'))
->getForm();
Now after form is submitted I have a handler which would check if the mail or username are not already taken
// Check if name or mail not occupied
if($user_manager->findUserByEmail($mail)){
}
elseif($user_manager->findUserByUsername($name)){
}
My goal is to, on mail/username occupied to have the form be printed again, only this time, occupied values would have a placeholder saying "THIS VALUE IS OCCUPIED"
Now I have tried to add another "add" into the if statement like
$form->add('newMail', TextType::class, array(
'required' => false,
'label' => "Change Email",
'attr' => array(
'placeholder' => "EMAIL TAKEN"
)
));
Unfortunately this returns me an error saying
You cannot add children to a submitted form
Now here is my question:
Is there a good and proper way to do it?
B-Side:
Could I trigger browser default validation like ie. In chrome if an input is required and you fail to put stuff there, the box would turn red and you would get an error message.
I was wondering if I could do the same here, so for this project so in that case I would get a red input box with alert "Email taken" or something like that
maybe something like this?
$form = $this->createFormBuilder($userSettings)
->add('newName', TextType::class, array(
'required' => false,
'label' => "Change UserName",
'attr' => array(
'placeholder' => $userData[0]->getUsername()
)
))
->add('newMail', TextType::class, array(
'required' => false,
'label' => "Change Email",
'attr' => array(
'placeholder' => $userData[0]->getEmail()
)
))
->add('newPassword', PasswordType::class, array(
'required' => false,
'label' => "Change Password"
))
->add('currentPassword', PasswordType::class, array(
'label' => "Current Password"
))
->add('save', SubmitType::class, array('label' => 'Update Information!'));
if(isset($mail) && $user_manager->findUserByEmail($mail)){
$form->remove('newMail')
->add('newMail', TextType::class, array(
'required' => false,
'label' => "Change Email",
'attr' => array(
'placeholder' => 'EMAIL TAKEN'
)
));
}
elseif(isset($name) && $user_manager->findUserByUsername($name)){
// just duplicate the above
}
$form->getForm();
Related
I'm building an Address form in Symfony 5.1.
It is created in an AddressType Class that has some required fields.
$builder
->add('name', TextType::class, [
'required' => false,
'label' => 'address.name',
'help' => 'address.name_help',
'attr' => [
'placeholder' => 'address.name_ph',
]
])
->add('company', TextType::class, [
'required' => false,
'label' => 'address.company',
'attr' => [
'placeholder' => 'address.company_ph',
]
])
->add('first_line', TextType::class, [
'label' => 'address.first_line',
'attr' => [
'placeholder' => 'address.first_line_ph',
]
])
->add('second_line', TextType::class, [
'required' => false,
'label' => 'address.second_line',
'attr' => [
'placeholder' => 'address.second_line_ph',
]
])
->add('add_info', TextType::class, [
'required' => false,
'label' => 'address.add_info',
'help' => 'address.add_info_help',
'attr' => [
'placeholder' => 'address.add_info_ph',
]
])
->add('postcode', TextType::class, [
'label' => 'address.postcode',
'attr' => [
'placeholder' => 'address.postcode_ph',
]
])
->add('city', TextType::class, [
'label' => 'address.city',
'attr' => [
'placeholder' => 'address.city_ph',
]
])
->add('state', TextType::class, [
'required' => false,
'label' => 'address.state',
'attr' => [
'placeholder' => 'address.state_ph',
]
])
->add('country', CountryType::class, [
'label' => 'address.country',
'preferred_choices' => ['FR'],
'attr' => [
'data-toggle' => 'select',
'placeholder' => 'address.country_ph',
]
])
->add('save',
SubmitType::class,
[
'label' => $options['submit_btn_label'],
]
);
If I submit this form with the submit button, everything works as expected, my form is being processed for validation and if It detects some errors, they are shown on each field.
Here is the function that handle the form :
public function new(Request $request)
{
$user = $this->getUser();
$address = new Address();
$address->setCreatedBy($user);
$form = $this->createForm(AddressType::class, $address);
//handle form
$form->handleRequest($request);
if ($form->isSubmitted()){
//if submit, add hidden fields
$address = $form->getData();
//if valid, process
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($address);
$em->flush();
$this->addFlash(
'success',
'Your address was created.'
);
return $this->redirectToRoute('address_index');
}
}
return $this->render('address/new.html.twig', [
'form' => $form->createView(),
'mode' => 'new',
]);
}
Now, If I submit this form through an AJAX request :
$(document).on('click', '.create-address', function() {
console.log('submitting new address form...');
var $form = $(this).closest('form')
var data = $form.serializeArray();
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data
});
});
In this case, my form is processed for validation and It passes ($form->isValid() returns true) even if I don't provide some of the required fields.
This causes the process of persisting the object to occur and so I get a PDOException.
My question is:
Why is my form not handled the same way (especially at the validation step) according how I post the data ?
And how different are those two methods from the point of view of the function that handle the request ?
The required option only adds the required attribute to the markup. This forces the browser to provide a value, but doesn't add any validation server side. You can trigger validation before your ajax call and submit only if the form status is valid.
But it is recommended to add server side validation explicitly by using the constraints option in the form or annotating the target entity. Refer to the documentation for more details.
I'm trying to submit a user form. But the form does not contain all database fields because I want to set the password later (when submitting form).
But now I'm getting the error that the field 'password' should not be blank. Removing the form validation is not working and adding them as HiddenType is also not working.
I'm getting this error after the $form->isValid() check
EDIT:
FormBuilder
$form = $this->createFormBuilder($user)
->add('email', TextType::class, array(
'label' => 'Email adres',
'attr' => array(
'class' => 'input-field'
)
))
->add('first_name', TextType::class, array(
'attr' => array(
'label' => 'Voornaam',
'class' => 'input-field'
)
))
->add('middle_name', TextType::class, array(
'label' => 'Tussenvoegsel (optioneel)',
'required' => false,
'attr' => array(
'class' => 'input-field'
)
))
->add('last_name', TextType::class, array(
'label' => 'Achternaam',
'attr' => array(
'class' => 'input-field'
)
))
->add('date_of_birth', DateType::class, array(
'label' => 'Geboortedatum',
'attr' => array(
'class' => 'input-field'
)
))
->add('save', SubmitType::class, array(
'label' => 'Gebruiker Opslaan',
'attr' => array(
'class' => 'form-submit-btn'
)
))
->getForm();
Submitting the form:
$form->handleRequest($request);
if($form->isSubmitted()){
if($form->isValid()){
dump($user);
exit;
}
}
EDIT:
Doing $user->setPassword('123'); before validation is not working
Can you post your User Entity?
You may get the Error because an argument is not allowed to be blank.
Take a look at any #Assert\NotBlank or nullable = false Annotations.
Can you show your User class? May be implements UserInterface? So, there is this validation.
I'm trying to generate a JSON of my form type in my controller using liform or liform-bundle but got the error :
CRITICAL - Uncaught PHP Exception Symfony\Component\Debug\Exception\UndefinedMethodException: "Attempted to call an undefined method named "getBlockPrefix" of class "Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeDataCollectorProxy"." at /home/admin/Documents/displayce/code/vendor/limenius/liform/src/Limenius/Liform/FormUtil.php line 39
the code in my controller :
$form = $this->createForm(new FormType(), $entity, array(
'method' => 'PUT',
'csrf_protection' => false,
));
$schema = json_encode($this->get('liform')->transform($form));
My form type code :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('startDate', 'date', array(
'label' => 'Start Date',
'required' => false,
'widget' => 'single_text',
'format' => 'dd/MM/yyyy',
'input' => 'datetime',
))
->add('endDate', 'date', array(
'label' => 'End Date (included)',
'required' => false,
'widget' => 'single_text',
'format' => 'dd/MM/yyyy',
'input' => 'datetime',
))
->add('name', 'text', array(
'label' => 'Name',
'max_length' => 255,
))
->add('budget', 'money', array(
'label' => 'Budget (target)',
'required' => true,
'scale' => 0, // not showing decimals
))
->add('target', 'targeting', array(
'cascade_validation' => true,
));
}
and the targeting type :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('contexts', 'entity', array(
'label' => 'Context(s)',
'class' => 'AppBundle\Entity\Context',
'choice_label' => 'name',
'expanded' => false,
'multiple' => true,
'required' => false,
))
->add('contextDetails', 'entity', array(
'label' => 'Detailed Context(s)',
'class' => 'AppBundle\Entity\ContextDetail',
'choice_label' => 'name',
'group_by' => 'context.name',
'expanded' => false,
'multiple' => true,
'required' => false,
))
->add('dataVariables', 'entity', array(
'label' => 'Variable',
'class' => 'AppBundle\Entity\DataVariable',
'choice_label' => 'name',
'expanded' => false,
'multiple' => true,
'group_by' => function($dataVariable, $key, $index) {
return $dataVariable->getDataProvider()->getName();
}
))
// Include criteria
->add('region', 'choice', array(
'label' => 'Region(s)',
'choices' => RegionDepartment::$regions,
'expanded' => false,
'multiple' => true,
'required' => false,
))
->add('department', 'choice', array(
'label' => 'Department(s)',
'choices' => RegionDepartment::$departments,
'expanded' => false,
'multiple' => true,
'required' => false,
))
;
It might be because I use a nested formtype ?
My goal if to combine symfony FormType with React Component so as long as you can redirect me to a solution to do that, i will me glad.
add a getBlockPrefix to your formType and targeting type like this :
public function getBlockPrefix()
{
return 'name of your form type';
}
I forked the bundle to change ->getBlockPrefix to ->getName() since the first one is not in Form.php in Symfony 2.7
I have a formtype, ContactoType, this form contain the next fields:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nombre','text', array(
'attr' => array(
'placeholder' => 'contacto.nombre'
)
))
->add('departamento', 'entity', array(
'label' => "Departamentos",
'class' => 'ProductosBundle:Departamento',
'property' => 'nombre'
))
->add('fechaEvento', 'birthday',array(
'input' => 'datetime',
'widget' => 'single_text',
'format' => 'dd-MM-yyyy',
'attr' => array(
'placeholder' => 'DD-MM-YYYY',
'class' => 'form-control')))
->add('promocion','text', array(
'attr' => array(
'placeholder' => 'contacto.promocion'
)
))
->add('apodo','text', array(
'attr' => array(
'placeholder' => 'contacto.apodo'
)
))
->add('file','file', array(
'attr' => array(
'placeholder' => 'contacto.fichero'
)
))
;
}
The Departamento entity has a field named "requiresadditional" if this is true, and promotion nickname will be displayed, if false they are hidden.
Do not know how you could get the field value "requiresadditional"...
As it should do this?Thank!
You should test your Departamento entity in a FormEvent. Read the documentation about FormEvents here.
Usually i add all the field to my symfony form and I display / hide the field by using simple javascript event.
I've inherited a Symfony2 project that has a form built as such:
$builder
->add('Status', 'choice', array(
'choices' => array('' => '', 'PASS' => 'PASS', 'FAIL' => 'FAIL', 'INCOMPLETE' => 'INCOMPLETE', 'DROPPED' => 'DROPPED',),
'required' => FALSE,
))
->add('First_Name', 'text', array('label'=>'First Name',
'required' => FALSE))
->add('Last_Name', 'text', array('label'=>'Last Name',
'required' => FALSE))
->add('PID', 'text', array('label'=>'License Number',
'required' => FALSE))
;
I need to have any letters entered in the PID field to be forced to uppercase. However I cannot find a option/attribute/... to do this.
Is there any way to do this?
If you use bootstrap this should work:
$builder
->add('Status', 'choice', array( 'choices' => array('' => '', 'PASS' => 'PASS', 'FAIL' => 'FAIL', 'INCOMPLETE' => 'INCOMPLETE', 'DROPPED' => 'DROPPED',),
'required' => FALSE,
'attr' => array( 'class' => 'text-uppercase' ),
))
I’m not sure if you ask for server-side validation or assistance for client-side uppercase input. In case of the latter: you could add a CSS class or a data-* attribute (something like ->add('PID', 'text', ['label'=>'License Number', 'required' => FALSE, 'attr' => ['data-behavior' => 'uppercase']])) to the PID element. Then, you could add a JavaScript event handler in the form (preferably using jQuery or some other framework) to automatically convert lowercase to uppercase letters on blur/change. (I would prefer the data-* attribute, as this has nothing to do with CSS.)
To enforce that on the server-side, you could use a #Assert\Regex annotation.