Reputation: 997
I'm writing my own CAPTCHA class and when the form doesn't validate, I don't want to pre-populate the captcha input with the previous answer, for obvious reasons. I just want to the clear the input before it's rendered.
I've discovered the data option is only for the default value, which is overwritten by what the user enters. I tried the following code:
$form->get('captcha')->setData(null);
.. After the request is bound with the form, but an AlreadyBoundException
is thrown. I have actually managed to get it working with:
if (isset($formView->children['captcha'])) {
$formView->children['captcha']->vars['value'] = null;
}
But that just looks wrong, and definitely not up to Symfony standards. I've looked through the other options you can provide when building the form, but I can't see anything of note.
Does anyone have any idea?
By the way, I half expect Symfony2 comes packaged with a CAPTCHA solution, this is mainly a learning exercise while I get used to the framework.
Upvotes: 11
Views: 7213
Reputation: 10144
I think you want to handle this form field like Symfony handles a password
field: it won't get populated. Let's take a look at the PasswordType:
namespace Symfony\Component\Form\Extension\Core\Type;
class PasswordType extends AbstractType
{
public function buildView(FormView $view, FormInterface $form, array $options)
{
if ($options['always_empty'] || !$form->isSubmitted()) {
$view->vars['value'] = '';
}
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'always_empty' => true,
'trim' => false,
));
}
//...
}
So, it's pretty simple: just add $view->vars['value'] = ''
in the buildView
method of your FormType (i.e. CaptchaType). That means the data of the field is not being cleared, but it won't be passed to the Twig template. Different approach, but the result is the same: the password field stays empty after validation failed.
If you are really lazy, you can use the PasswordType, but since the input of that field will be masked (*****), will that make an annoying captcha field even worse.
Your Form Type maybe look like this:
class CaptchaType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
$view->vars['value'] = '';
}
/**
* {@inheritdoc}
*/
public function getParent()
{
return __NAMESPACE__.'\TextType';
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->getBlockPrefix();
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'captcha';
}
}
Edit: Just found that CaptchaBundle took the same approach.
Upvotes: 5
Reputation: 4633
There is a funny way to modify the Request before handling it. However I'd look into Stephan's answer as it seems more clean.
Something like so:
public function indexAction(Request $request)
{
$form = $this->createForm(Form::class);
$subData=$request->request->get('form');
$subData['task']=null;
$request->request->set('form',$subData);
$form->handleRequest($request);
if ($form->isValid()) {
//do stuff
}
return $this->render('default/index.html.twig', array(
'form' => $form->createView()
));
}
Get submitted data with the name 'form' as an array of values, change the said value to null, then set the request's value with the new one and have the form handle it.
And a simple form
class Form extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('task')
->add('save', SubmitType::class);
}
}
No matter what you type, the data will always be null after submitting the form. Of course, you need to verify the captcha before setting the value to null.
Upvotes: 3
Reputation: 3656
You can pass an incomplete entity to the action called when your control finds form invalid.
public function updateAction(Request $request, $id) { $entity = $this->EM()->getRepository('Bundle:Entity')->find($id); if (!$entity) { throw $this->createNotFoundException('Unable to find Entity entity.'); } $form = $this->createForm(new RecommendationType() ,$entity ,array( 'attr' => array( ,'entity' => $entity ) ) ); $form->bind($request); if ($form->isValid()) { $this->EM()->persist($entity); $this->EM()->flush(); return $this->redirect($this->generateUrl('entity_show' ,array('id' => $id))); } else { $entity->setCapthca(Null); } return $this->render('Bundle:Entity:edit.html.twig' ,array( 'entity' => $entity ,'form' => $form->createView() ) ); }
The create action would have similar modification.
Upvotes: 0