All the fields of a Form Type are usually used everywhere, but there are cases when a field shouldn't appear in some sections of your app for some reasons. Obviously you won't render the fields in the frontend and hide them with CSS, DON'T DO THAT, PLEASE. In such cases you can remove the fields from the Form Type easily so you don't need to create an incomplete Form Type and then write the conditional fields in the controllers.
For example, in this article we are going to use the following FormType
namely UserType
:
<?php
namespace userBundle\Form;
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\TextareaType;
class UserType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class , array(
"attr" => array(
"class" => "form-control"
)
))
->add('username', TextType::class, array(
"attr" => array(
"class" => "form-control"
)
))
->add('description', TextareaType::class, array(
"attr" => array(
"class" => "form-control",
"maxlength" => 255
)
))
->add('password', RepeatedType::class, array(
'type' => PasswordType::class,
'invalid_message' => 'The password fields must match.',
'options' => array(
'attr' => array(
'class' => 'form-control'
)
),
'required' => true,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
))
;
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'userbundle_user';
}
}
This FormType has 4 fields: name, username, description and password. This form will be used in 2 actions : newAction
and editAction
. While working in the newAction
we won't need to remove any field, however when the user edits, we will need to remove the password field and it can be achieved in two ways:
A. Removing field using the remove method
From the returned object by the createForm
method, simply invoke the remove method of the Form class:
<?php
namespace userBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
// Classes of the example
use userBundle\Form\UserType;
use userBundle\Entity\User;
class UserController extends Controller
{
// .. //
public function editAction(Request $request, $id){
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository("userBundle:User")->find($id);
if(!$user){
throw $this->createNotFoundException("The providen user doesn't exist with id $id");
}
// Prepare Form
$editForm = $this->createForm(UserType::class, $user);
// Remove the password field !
$editForm->remove('password');
// Rest of the code ...
}
// .. //
}
This will simply remove the field from the Form and that's it.
B. Filtering using options in the buildForm
As you may (or maybe not) know, the createForm
method expects as third argument an array with options:
/**
* Creates and returns a Form instance from the type of the form.
*
* @param string $type The fully qualified class name of the form type
* @param mixed $data The initial data for the form
* @param array $options Options for the form
*
* @return Form
*/
protected function createForm($type, $data = null, array $options = array()){}
that is sent to the buildForm
function as second argument in the Form Type class:
public function buildForm(FormBuilderInterface $builder, array $options)
So you can use a simple "flag" argument that specifies (only if defined) to render the password field or not, for example you will need to modify your type and add a conditional with the options:
<?php
namespace userBundle\Form;
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\TextareaType;
class UserType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class , array(
"attr" => array(
"class" => "form-control"
)
))
->add('username', TextType::class, array(
"attr" => array(
"class" => "form-control"
)
))
->add('description', TextareaType::class, array(
"attr" => array(
"class" => "form-control",
"maxlength" => 255
)
))
;
// If the usePassword options is set to true,
if($options["usePassword"]){
$builder->add('password', RepeatedType::class, array(
'type' => PasswordType::class,
'invalid_message' => 'The password fields must match.',
'options' => array(
'attr' => array(
'class' => 'form-control'
)
),
'required' => true,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat Password'),
));
}
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
// Set by default when the options aren't providen, use the password
$resolver->setDefaults(array(
'usePassword' => true
));
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'userbundle_user';
}
}
Note that you need to use the setDefaultOptions
to specify the value when the third argument isn't providen during the creation of the form. And finally in your controller specify an array with the options, that in this case is only ona namely usePassword
with a boolean value:
<?php
namespace userBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
// Classes of the example
use userBundle\Form\UserType;
use userBundle\Entity\User;
class UserController extends Controller
{
// .. //
public function editAction(Request $request, $id){
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository("userBundle:User")->find($id);
if(!$user){
throw $this->createNotFoundException("The providen user doesn't exist with id $id");
}
// Prepare Form and remove the password field
$editForm = $this->createForm(UserType::class, $user , [
'usePassword' => false
]);
// Rest of the code ...
}
// .. //
}
Happy coding !